enh(os::linux::local): adding support for timedatectl to ntp mode (#5723)

Refs: CTOR-672
This commit is contained in:
Sylvain Cresto 2025-08-29 10:43:45 +02:00 committed by GitHub
parent c185a4f1f1
commit 18cf4c1707
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 415 additions and 30 deletions

View File

@ -68,6 +68,28 @@ my %unit_map_chronyc = (
's' => 1000 's' => 1000
); );
my %unit_map_timedatectl = (
'us' => 0.001,
'ms' => 1,
's' => 1000,
'min' => 60 * 1000,
'h' => 60 * 60 * 1000,
'd' => 24 * 60 *60 * 1000
);
my %state_map_timedatectl = (
'synchronized' => 'currently active and fully synchronized',
'syncing' => 'currently active and synchronizing',
'available' => 'configured and available for use',
'unused' => 'configured as fallback but not used',
'inactive' => 'not used because NTP service is inactive'
);
my %type_map_timedatectl = (
'primary' => 'Primary NTP Server',
'fallback' => 'Fallback NTP Server'
);
sub custom_status_output { sub custom_status_output {
my ($self, %options) = @_; my ($self, %options) = @_;
@ -82,7 +104,7 @@ sub custom_status_output {
sub custom_offset_perfdata { sub custom_offset_perfdata {
my ($self, %options) = @_; my ($self, %options) = @_;
if ($self->{result_values}->{rawstate} ne '*') { if ($self->{result_values}->{rawstate} !~ /(\*|synchronized)/) {
$self->{output}->perfdata_add( $self->{output}->perfdata_add(
nlabel => $self->{nlabel}, nlabel => $self->{nlabel},
unit => 'ms', unit => 'ms',
@ -106,9 +128,8 @@ sub custom_offset_perfdata {
sub custom_offset_threshold { sub custom_offset_threshold {
my ($self, %options) = @_; my ($self, %options) = @_;
if ($self->{result_values}->{rawstate} ne '*') { return 'ok' if $self->{result_values}->{rawstate} !~ /^(\*|synchronized)$/;
return 'ok';
}
return $self->{perfdata}->threshold_check(value => $self->{result_values}->{offset}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } ]); return $self->{perfdata}->threshold_check(value => $self->{result_values}->{offset}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } ]);
} }
@ -176,9 +197,11 @@ sub new {
bless $self, $class; bless $self, $class;
$options{options}->add_options(arguments => { $options{options}->add_options(arguments => {
'ntp-mode:s' => { name => 'ntp_mode', default => 'ntpq' }, 'ntp-mode:s' => { name => 'ntp_mode', default => 'auto' },
'filter-name:s' => { name => 'filter_name' }, 'filter-name:s' => { name => 'filter_name', default => '' },
'filter-state:s' => { name => 'filter_state' } 'exclude-name:s' => { name => 'exclude_name', default => '' },
'filter-state:s' => { name => 'filter_state', default => '' },
'exclude-state:s' => { name => 'exclude_state', default => '' }
}); });
return $self; return $self;
@ -188,7 +211,7 @@ sub check_options {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->SUPER::check_options(%options); $self->SUPER::check_options(%options);
if ($self->{option_results}->{ntp_mode} !~ /^(?:ntpq|chronyc|all)$/) { if ($self->{option_results}->{ntp_mode} !~ /^(ntpq|chronyc|timedatectl|all|auto)$/) {
$self->{output}->add_option_msg(short_msg => "ntp mode '" . $self->{option_results}->{ntp_mode} . "' not implemented" ); $self->{output}->add_option_msg(short_msg => "ntp mode '" . $self->{option_results}->{ntp_mode} . "' not implemented" );
$self->{output}->option_exit(); $self->{output}->option_exit();
} }
@ -209,39 +232,186 @@ sub get_ntp_modes {
command => 'chronyc', command => 'chronyc',
command_options => '-n sources 2>&1', command_options => '-n sources 2>&1',
type => 'chronyc' type => 'chronyc'
},
timedatectl => {
regexp => '',
command => '',
command_options => '',
type => 'timedatectl'
} }
}; };
if ($self->{option_results}->{ntp_mode} eq 'ntpq') { # Returns the selected mode or all modes
return [ $modes->{ntpq} ]; return [ $modes->{$self->{option_results}->{ntp_mode}} ?
} elsif ($self->{option_results}->{ntp_mode} eq 'chronyc') { $modes->{$self->{option_results}->{ntp_mode}} :
return [ $modes->{chronyc} ]; ( $modes->{timedatectl}, $modes->{chronyc}, $modes->{ntpq} ) ];
}
sub skip_record {
my ($self, %options) = @_;
my $name = $options{display} // '';
my $address = $options{address} // '';
my $rawstate = $options{rawstate} // '';
my $state = $options{state} // '';
# filter_name includes name and address
if ($self->{option_results}->{filter_name} ne '' && $name !~ /$self->{option_results}->{filter_name}/ && $address !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '$name': no matching filter peer name.", debug => 1);
return 1;
}
if ($self->{option_results}->{exclude_name} ne '' && ($name =~ /$self->{option_results}->{exclude_name}/ || $address =~ /$self->{option_results}->{exclude_name}/)) {
$self->{output}->output_add(long_msg => "skipping '$name': excluded peer name.", debug => 1);
return 1;
} }
return [ $modes->{chronyc}, $modes->{ntpq} ]; if ($self->{option_results}->{filter_state} ne '' && $state !~ /$self->{option_results}->{filter_state}/ && $rawstate !~ /$self->{option_results}->{filter_state}/) {
$self->{output}->output_add(long_msg => "skipping '$name': no matching filter peer state.", debug => 1);
return 1;
}
if ($self->{option_results}->{exclude_state} ne '' && ($state =~ /$self->{option_results}->{exclude_state}/ || $rawstate =~ /$self->{option_results}->{exclude_state}/)) {
$self->{output}->output_add(long_msg => "skipping '$name': excluded peer state.", debug => 1);
return 1;
}
return 0;
}
sub manage_timedatectl {
my ($self, %options) = @_;
# With timedatectl three calls are required to retrieve all information
#
# timedatectl status to retrieve 'NTP service' and 'System clock synchronized'
# Output snippet:
# System clock synchronized: yes
# NTP service: active
#
# timedatectl timesync-status to retrieve 'Offset', 'Stratum' and 'Packet count'
# Output snippet:
# Version: 4
# Stratum: 2
# Offset: -398us
# Jitter: 150us
# Packet count: 2
#
# timedatectl show-timesync to retrieve 'SystemNTPServers', 'FallbackNTPServers', 'ServerAddress' and 'ServerName'
# Output snippet:
# SystemNTPServers=0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org
# FallbackNTPServers=3.pool.ntp.org 4.pool.ntp.org
# ServerName=0.pool.ntp.org
# ServerAddress=188.125.64.7
# PollIntervalUSec=4min 16s
# NTPMessage={ Leap=0, Version=4, Mode=4, Stratum=2, Precision=-25, RootDelay=79.940ms, RootDispersion=1.358ms, Reference=628B853E, OriginateTimestamp=Thu 2025-08-28 14:31:58 CEST, ReceiveTimestamp=Thu 2025-08-28 14:31:58 CEST, TransmitTimestamp=Thu 2025-08-28 14:31:58 CEST, DestinationTimestamp=Thu 2025-08-28 14:31:58 CEST, Ignored=no PacketCount=3, Jitter=573us }
my ($stdout_status) = $options{custom}->execute_command( command => 'timedatectl',
command_options => 'status 2>&1',
no_quit => 1, );
my ($stdout_timesync) = $options{custom}->execute_command( command => 'timedatectl',
command_options => 'timesync-status 2>&1',
no_quit => 1, );
my ($stdout_show) = $options{custom}->execute_command( command => 'timedatectl',
command_options => 'show-timesync 2>&1',
no_quit => 1, );
my %values = ( ( map { /^\s*(.+?): (.+)$/ } split /\n/, $stdout_timesync ),
( map { /^(.+?)=(.+)$/ } split /\n/, $stdout_show ),
( map { /^\s*(.+?): (.+)$/ } split /\n/, $stdout_status ) );
return "timedatectl not available" unless $values{'NTP service'};
$values{$_}//='' foreach ('SystemNTPServers', 'FallbackNTPServers', 'ServerAddress', 'ServerName', 'Offset', 'Stratum', 'Packet count', 'System clock synchronized');
my $active_is_fallback = 0;
# Primary and fallback servers are initialized, the active server is excluded as it will be initialized later with additional information
# A server has either the type 'primary' or 'fallback'
# A 'primary' server can have the states 'available', 'synchronized', 'syncing' or 'inactive'
# A 'fallback' server can have the states 'unused', synchronized', 'syncing' or 'inactive'
foreach my $srv (split /\s/, $values{SystemNTPServers}) {
next if $values{ServerAddress} && ($srv eq $values{ServerAddress} || $srv eq $values{ServerName});
$self->{peers}->{$srv} = { display => $srv, rawstate => 'available', stratum => 0, rawtype => 'primary', reach => 0, offset => 0 };
$self->{global}->{peers}++
}
foreach my $srv (split /\s/, $values{FallbackNTPServers}) {
if ($values{ServerAddress} && ($srv eq $values{ServerAddress} || $srv eq $values{ServerName})) {
$active_is_fallback = 1;
next
}
$self->{peers}->{$srv} = { display => $srv, rawstate => 'unused', stratum => 0, rawtype => 'fallback', reach => 0, offset => 0 };
$self->{global}->{peers}++
}
if ($values{ServerAddress} ne '') {
# If there is an active server it is initialized here with all information
$values{ServerName} = $values{ServerAddress} if $values{ServerName} eq '';
$values{'Offset'} = $1 * $unit_map_timedatectl{$2} if $values{'Offset'} =~ /^(.*?)([a-z]+)$/ && $unit_map_timedatectl{$2};
$self->{peers}->{$values{ServerAddress}} = { display => $values{ServerName},
address => $values{ServerAddress},
rawstate => $values{'System clock synchronized'} eq 'yes' ? 'synchronized' : 'syncing',
rawtype => $active_is_fallback ? 'fallback' : 'primary',
stratum => $values{Stratum},
reach => $values{'Packet count'},
offset => $values{'Offset'} };
$self->{global}->{peers}++;
}
foreach my $peer (keys %{$self->{peers}}) {
$self->{peers}->{$peer}->{rawstate} = 'inactive' if $values{'NTP service'} ne 'active';
$self->{peers}->{$peer}->{state} = $state_map_timedatectl{$self->{peers}->{$peer}->{rawstate}};
$self->{peers}->{$peer}->{type} = $type_map_timedatectl{$self->{peers}->{$peer}->{rawtype}};
# Data is only filtered here becase all states must be initialized first
if ($self->skip_record(%{$self->{peers}->{$peer}})) {
delete $self->{peers}->{$peer};
$self->{global}->{peers}--;
next
}
}
undef;
} }
sub manage_selection { sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
my $request_mode = $self->{option_results}->{ntp_mode};
my $no_quit = $self->{option_results}->{ntp_mode} =~ /^(all|auto)$/;
my $modes = $self->get_ntp_modes(); my $modes = $self->get_ntp_modes();
$self->{global} = { peers => 0 }; $self->{global} = { peers => 0 };
$self->{peers} = {}; $self->{peers} = {};
foreach my $mode (@$modes) { foreach my $mode (@$modes) {
# Exit if we are in auto mode and the previous mode has already found peers
last if $self->{global}->{peers} && $request_mode eq 'auto';
if ($mode->{type} eq 'timedatectl') {
# timedatectl differs from other modes so it is handled in its own function
my $error = $self->manage_timedatectl( custom => $options{custom} );
if ($no_quit == 0 && $error) {
$self->{output}->add_option_msg(short_msg => $error);
$self->{output}->option_exit();
}
next
}
my ($stdout) = $options{custom}->execute_command( my ($stdout) = $options{custom}->execute_command(
command => $mode->{command}, command => $mode->{command},
command_options => $mode->{command_options}, command_options => $mode->{command_options},
no_quit => $self->{option_results}->{ntp_mode} eq 'all' ? 1 : undef no_quit => $no_quit
); );
my @lines = split(/\n/, $stdout); my @lines = split /\n/, $stdout;
foreach my $line (@lines) { foreach my $line (@lines) {
if ($self->{option_results}->{ntp_mode} ne 'all' && $line =~ /Connection refused/) { if ($no_quit == 0 && $line =~ /Connection refused/) {
$self->{output}->add_option_msg(short_msg => "check ntp.conf and ntp daemon" ); $self->{output}->add_option_msg(short_msg => "check ntp.conf and ntp daemon" );
$self->{output}->option_exit(); $self->{output}->option_exit();
} }
next if ($line !~ /$mode->{regexp}/); next if $line !~ /$mode->{regexp}/;
my $entry = {}; my $entry = {};
my ($remote_peer, $peer_fate) = (centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($1)); my ($remote_peer, $peer_fate) = (centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($1));
@ -273,16 +443,7 @@ sub manage_selection {
}; };
} }
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && next if $self->skip_record(%$entry);
$remote_peer !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $remote_peer . "': no matching filter peer name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_state}) && $self->{option_results}->{filter_state} ne '' &&
$peer_fate !~ /$self->{option_results}->{filter_state}/) {
$self->{output}->output_add(long_msg => "skipping '" . $remote_peer . "': no matching filter peer state.", debug => 1);
next;
}
if ($mode->{type} eq 'ntpq') { if ($mode->{type} eq 'ntpq') {
my ($refid, $stratum, $type, $last_time, $polling_intervall, $reach, $delay, $offset, $jitter) = ($3, $4, $5, $6, $7, $8, $9, $10, $11); my ($refid, $stratum, $type, $last_time, $polling_intervall, $reach, $delay, $offset, $jitter) = ($3, $4, $5, $6, $7, $8, $9, $10, $11);
@ -308,24 +469,34 @@ __END__
=head1 MODE =head1 MODE
Check ntp daemons. Check NTP daemons.
Command used: 'ntpq -p -n 2>&1' or 'chronyc -n sources 2>&1' Command used: C<timedatectl status ; timedatectl timesync-status ; timedatectl show-timesync> or C<ntpq -p -n> or C<chronyc -n sources>
=over 8 =over 8
=item B<--ntp-mode> =item B<--ntp-mode>
Default mode for parsing and command: 'ntpq' (default), 'chronyc' or 'all'. Default mode for parsing and command: C<auto> (default), C<timedatectl>, C<ntpq>, C<chronyc> or C<all>.
In 'auto' mode the data is taken from the first working mode (in order).
In 'all' mode the data is taken and aggregated from all working mode.
=item B<--filter-name> =item B<--filter-name>
Filter peer name (can be a regexp). Filter peer name (can be a regexp).
=item B<--exclude-name>
Exclude by peer name (can be a regexp).
=item B<--filter-state> =item B<--filter-state>
Filter peer state (can be a regexp). Filter peer state (can be a regexp).
=item B<--exclude-state>
Exclude by peer state (can be a regexp).
=item B<--warning-peers> =item B<--warning-peers>
Warning threshold minimum amount of NTP-Server Warning threshold minimum amount of NTP-Server

View File

@ -0,0 +1,67 @@
*** Settings ***
Documentation Linux Local ntp
Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource
Test Timeout 120s
Suite Setup Ctn Generic Suite Setup
Suite Teardown Ctn Generic Suite Teardown
*** Variables ***
${CMD} ${CENTREON_PLUGINS} --plugin=os::linux::local::plugin
*** Test Cases ***
ntp auto ${tc}
[Tags] os linux local
${command} Catenate
... ${CMD}
... --mode=ntp
... --command-path=${CURDIR}${/}ntp_all_bin
... ${extra_options}
Ctn Run Command And Check Result As Strings ${command} ${expected_result}
Examples: tc extra_options expected_result --
... 1 ${EMPTY} OK: Number of ntp peers: 5 - All peers are ok | 'peers.detected.count'=5;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;;;0; '0.pool.ntp.org#peer.stratum.count'=1;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;;0;
... 2 --filter-name='^[1-3]' --exclude-name='^2' OK: Number of ntp peers: 2 - All peers are ok | 'peers.detected.count'=2;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0;
... 3 --filter-state='.*configured.*' --exclude-state='.*fallback.*' OK: Number of ntp peers: 2 - All peers are ok | 'peers.detected.count'=2;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0;
... 4 --critical-peers='10:' CRITICAL: Number of ntp peers: 5 | 'peers.detected.count'=5;;10:;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;;;0; '0.pool.ntp.org#peer.stratum.count'=1;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;;0;
... 5 --warning-offset='3:' WARNING: Peer '0.pool.ntp.org' offset: 2.957 ms | 'peers.detected.count'=5;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;3:;;0; '0.pool.ntp.org#peer.stratum.count'=1;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;;0;
... 6 --critical-stratum='1:' CRITICAL: Peer '1.pool.ntp.org' stratum: 0 - Peer '2.pool.ntp.org' stratum: 0 - Peer '3.pool.ntp.org' stratum: 0 - Peer '4.pool.ntp.org' stratum: 0 | 'peers.detected.count'=5;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;1:;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;;;0; '0.pool.ntp.org#peer.stratum.count'=1;;1:;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;1:;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;1:;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;1:;0;
... 7 --ntp-mode=auto OK: Number of ntp peers: 5 - All peers are ok | 'peers.detected.count'=5;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;;;0; '0.pool.ntp.org#peer.stratum.count'=1;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;;0;
... 8 --ntp-mode=chronyc OK: Number of ntp peers: 8 - All peers are ok | 'peers.detected.count'=8;;;0; '185.125.190.56#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.56#peer.stratum.count'=2;;;0; '185.125.190.57#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.57#peer.stratum.count'=2;;;0; '188.125.64.7#peer.time.offset.milliseconds'=60ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2606:4700:f1::123#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::123#peer.stratum.count'=3;;;0; '2620:2d:4000:1::3f#peer.time.offset.milliseconds'=14ms;;;0; '2620:2d:4000:1::3f#peer.stratum.count'=2;;;0; '88.81.100.130#peer.time.offset.milliseconds'=22ms;;;0; '88.81.100.130#peer.stratum.count'=1;;;0; '91.189.91.157#peer.time.offset.milliseconds'=81ms;;;0; '91.189.91.157#peer.stratum.count'=2;;;0;
... 9 --ntp-mode=ntpq OK: Number of ntp peers: 7 - All peers are ok | 'peers.detected.count'=7;;;0; '162.159.200.1#peer.time.offset.milliseconds'=+1.681ms;;;0; '162.159.200.1#peer.stratum.count'=3;;;0; '162.159.200.123#peer.time.offset.milliseconds'=+18.266ms;;;0; '162.159.200.123#peer.stratum.count'=3;;;0; '188.125.64.7#peer.time.offset.milliseconds'=-10.248ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '193.1.12.167#peer.time.offset.milliseconds'=-20.845ms;;;0; '193.1.12.167#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=-0.426ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2a00:1288:110:f#peer.time.offset.milliseconds'=-0.069ms;;;0; '2a00:1288:110:f#peer.stratum.count'=2;;;0;
... 10 --ntp-mode=all OK: Number of ntp peers: 20 - All peers are ok | 'peers.detected.count'=20;;;0; '1.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '1.pool.ntp.org#peer.stratum.count'=0;;;0; '162.159.200.1#peer.time.offset.milliseconds'=+1.681ms;;;0; '162.159.200.1#peer.stratum.count'=3;;;0; '162.159.200.123#peer.time.offset.milliseconds'=+18.266ms;;;0; '162.159.200.123#peer.stratum.count'=3;;;0; '185.125.190.56#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.56#peer.stratum.count'=2;;;0; '185.125.190.57#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.57#peer.stratum.count'=2;;;0; '188.125.64.7#peer.time.offset.milliseconds'=-10.248ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '193.1.12.167#peer.time.offset.milliseconds'=-20.845ms;;;0; '193.1.12.167#peer.stratum.count'=2;;;0; '0.pool.ntp.org#peer.time.offset.milliseconds'=2.957ms;;;0; '0.pool.ntp.org#peer.stratum.count'=1;;;0; '2.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '2.pool.ntp.org#peer.stratum.count'=0;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=-0.426ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2606:4700:f1::123#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::123#peer.stratum.count'=3;;;0; '2620:2d:4000:1::3f#peer.time.offset.milliseconds'=14ms;;;0; '2620:2d:4000:1::3f#peer.stratum.count'=2;;;0; '2a00:1288:110:f#peer.time.offset.milliseconds'=-0.069ms;;;0; '2a00:1288:110:f#peer.stratum.count'=2;;;0; '3.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '3.pool.ntp.org#peer.stratum.count'=0;;;0; '4.pool.ntp.org#peer.time.offset.milliseconds'=0ms;;;0; '4.pool.ntp.org#peer.stratum.count'=0;;;0; '88.81.100.130#peer.time.offset.milliseconds'=22ms;;;0; '88.81.100.130#peer.stratum.count'=1;;;0; '91.189.91.157#peer.time.offset.milliseconds'=81ms;;;0; '91.189.91.157#peer.stratum.count'=2;;;0;
ntp chronyc ${tc}
[Tags] os linux local
${command} Catenate
... ${CMD}
... --mode=ntp
... --command-path=${CURDIR}${/}ntp_chrony_bin
... ${extra_options}
Ctn Run Command And Check Result As Strings ${command} ${expected_result}
Examples: tc extra_options expected_result --
... 0 ${EMPTY} OK: Number of ntp peers: 8 - All peers are ok | 'peers.detected.count'=8;;;0; '185.125.190.56#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.56#peer.stratum.count'=2;;;0; '185.125.190.57#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.57#peer.stratum.count'=2;;;0; '188.125.64.7#peer.time.offset.milliseconds'=60ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2606:4700:f1::123#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::123#peer.stratum.count'=3;;;0; '2620:2d:4000:1::3f#peer.time.offset.milliseconds'=14ms;;;0; '2620:2d:4000:1::3f#peer.stratum.count'=2;;;0; '88.81.100.130#peer.time.offset.milliseconds'=22ms;;;0; '88.81.100.130#peer.stratum.count'=1;;;0; '91.189.91.157#peer.time.offset.milliseconds'=81ms;;;0; '91.189.91.157#peer.stratum.count'=2;;;0;
... 1 --ntp-mode=chronyc OK: Number of ntp peers: 8 - All peers are ok | 'peers.detected.count'=8;;;0; '185.125.190.56#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.56#peer.stratum.count'=2;;;0; '185.125.190.57#peer.time.offset.milliseconds'=25ms;;;0; '185.125.190.57#peer.stratum.count'=2;;;0; '188.125.64.7#peer.time.offset.milliseconds'=60ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2606:4700:f1::123#peer.time.offset.milliseconds'=18ms;;;0; '2606:4700:f1::123#peer.stratum.count'=3;;;0; '2620:2d:4000:1::3f#peer.time.offset.milliseconds'=14ms;;;0; '2620:2d:4000:1::3f#peer.stratum.count'=2;;;0; '88.81.100.130#peer.time.offset.milliseconds'=22ms;;;0; '88.81.100.130#peer.stratum.count'=1;;;0; '91.189.91.157#peer.time.offset.milliseconds'=81ms;;;0; '91.189.91.157#peer.stratum.count'=2;;;0;
ntp ntpq ${tc}
[Tags] os linux local
${command} Catenate
... ${CMD}
... --mode=ntp
... --command-path=${CURDIR}${/}ntp_ntpq_bin
... ${extra_options}
Ctn Run Command And Check Result As Strings ${command} ${expected_result}
Examples: tc extra_options expected_result --
... 0 ${EMPTY} OK: Number of ntp peers: 7 - All peers are ok | 'peers.detected.count'=7;;;0; '162.159.200.1#peer.time.offset.milliseconds'=+1.681ms;;;0; '162.159.200.1#peer.stratum.count'=3;;;0; '162.159.200.123#peer.time.offset.milliseconds'=+18.266ms;;;0; '162.159.200.123#peer.stratum.count'=3;;;0; '188.125.64.7#peer.time.offset.milliseconds'=-10.248ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '193.1.12.167#peer.time.offset.milliseconds'=-20.845ms;;;0; '193.1.12.167#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=-0.426ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2a00:1288:110:f#peer.time.offset.milliseconds'=-0.069ms;;;0; '2a00:1288:110:f#peer.stratum.count'=2;;;0;
... 1 --ntp-mode=ntpq OK: Number of ntp peers: 7 - All peers are ok | 'peers.detected.count'=7;;;0; '162.159.200.1#peer.time.offset.milliseconds'=+1.681ms;;;0; '162.159.200.1#peer.stratum.count'=3;;;0; '162.159.200.123#peer.time.offset.milliseconds'=+18.266ms;;;0; '162.159.200.123#peer.stratum.count'=3;;;0; '188.125.64.7#peer.time.offset.milliseconds'=-10.248ms;;;0; '188.125.64.7#peer.stratum.count'=2;;;0; '193.1.12.167#peer.time.offset.milliseconds'=-20.845ms;;;0; '193.1.12.167#peer.stratum.count'=2;;;0; '2606:4700:f1::1#peer.time.offset.milliseconds'=-0.426ms;;;0; '2606:4700:f1::1#peer.stratum.count'=3;;;0; '2a00:1288:110:f#peer.time.offset.milliseconds'=-0.069ms;;;0; '2a00:1288:110:f#peer.stratum.count'=2;;;0;

View File

@ -0,0 +1,19 @@
#!/bin/sh
if [ "$1" = "-n" ] && [ "$2" = "sources" ]; then
cat<<EOF
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^+ 185.125.190.57 2 6 17 2 -714us[ -36us] +/- 25ms
^- 91.189.91.157 2 6 17 0 -3120us[-2441us] +/- 81ms
^+ 185.125.190.56 2 6 17 1 -444us[ +234us] +/- 25ms
^* 2620:2d:4000:1::3f 2 6 17 0 +441us[+1119us] +/- 14ms
^- 188.125.64.7 2 6 17 1 +334us[+1012us] +/- 60ms
^+ 88.81.100.130 1 6 17 2 -173us[ +505us] +/- 22ms
^+ 2606:4700:f1::123 3 6 17 1 +334us[+1013us] +/- 18ms
^+ 2606:4700:f1::1 3 6 17 1 +555us[+1234us] +/- 18ms
EOF
else
echo "Failed"
fi

View File

@ -0,0 +1,29 @@
#/bin/sh
if [ "$1" = "-p" ] && [ "$2" = "-n" ]; then
cat<<EOF
remote refid st t when poll reach delay offset jitter
==============================================================================
0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
2.rhel.pool.ntp .POOL. 16 p - 64 0 0.000 +0.000 0.000
+188.125.64.7 98.139.133.62 2 u 56 64 1 80.986 -10.248 20.809
-193.1.12.167 193.1.8.106 2 u 54 64 1 146.953 -20.845 14.280
-162.159.200.123 10.52.8.17 3 u 51 64 1 74.911 +18.266 20.879
*2a00:1288:110:f 31.60.135.175 2 u 54 64 1 35.304 -0.409 0.771
-2a00:1288:110:f 98.139.133.62 2 u 49 64 1 34.100 -0.069 0.503
-162.159.200.1 10.52.8.17 3 u 51 64 1 40.444 +1.681 10.464
+2606:4700:f1::1 10.215.8.4 3 u 52 64 1 18.389 -0.426 0.822
188.125.64.6 31.60.135.175 2 u 47 64 1 139.867 -19.354 24.647
2001:770:101:2: .GNSS. 1 u 62 64 1 35.393 +1.100 0.000
2001:770:101::2 .GNSS. 1 u 61 64 1 41.811 +3.700 0.000
88.81.100.130 .GPS. 1 u 48 64 1 66.919 -11.980 10.431
89.234.64.77 193.120.142.71 2 u 60 64 1 36.277 +0.195 0.000
85.91.1.164 193.120.10.3 2 u 57 64 1 148.037 -22.339 0.000
85.91.1.180 195.66.241.2 2 u 58 64 1 36.309 +0.183 0.000
EOF
else
echo "Failed"
fi

View File

@ -0,0 +1,51 @@
#!/bin/sh
case "$1" in
status|"")
cat<<EOF
Local time: jeu. 2025-08-28 10:48:59 CEST
Universal time: jeu. 2025-08-28 08:48:59 UTC
RTC time: jeu. 2025-08-28 08:48:59
Time zone: Europe/Paris (CEST, +0200)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
EOF
;;
timesync-status)
cat<<EOF
Server: 52.17.231.73 (0.pool.ntp.org)
Poll interval: 34min 8s (min: 32s; max 34min 8s)
Leap: normal
Version: 4
Stratum: 1
Reference: PHC0
Precision: 1us (-25)
Root distance: 22us (max: 5s)
Offset: +2.957ms
Delay: 38.947ms
Jitter: 512.304ms
Packet count: 20
Frequency: +12,565ppm
EOF
;;
show-timesync)
cat<<EOF
SystemNTPServers=0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org
FallbackNTPServers=3.pool.ntp.org 4.pool.ntp.org
ServerName=0.pool.ntp.org
ServerAddress=2.3.4.5
RootDistanceMaxUSec=5s
PollIntervalMinUSec=32s
PollIntervalMaxUSec=34min 8s
PollIntervalUSec=34min 8s
NTPMessage={ Leap=0, Version=4, Mode=4, Stratum=1, Precision=-25, RootDelay=15us, RootDispersion=15us, Reference=PHC0, OriginateTimestamp=Thu 2025-08-28 10:41:54 CEST, ReceiveTimestamp=Thu 2025-08-28 10:41:54 CEST, TransmitTimestamp=Thu 2025-08-28 10:41:54 CEST, DestinationTimestamp=Thu 2025-08-28 10:41:54 CEST, Ignored=no PacketCount=20, Jitter=512.304ms }
Frequency=823454
EOF
;;
*)
echo "Timedatectl: unrecognized option '$1'"
exit 1
;;
esac

View File

@ -0,0 +1,19 @@
#!/bin/sh
if [ "$1" = "-n" ] && [ "$2" = "sources" ]; then
cat<<EOF
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^+ 185.125.190.57 2 6 17 2 -714us[ -36us] +/- 25ms
^- 91.189.91.157 2 6 17 0 -3120us[-2441us] +/- 81ms
^+ 185.125.190.56 2 6 17 1 -444us[ +234us] +/- 25ms
^* 2620:2d:4000:1::3f 2 6 17 0 +441us[+1119us] +/- 14ms
^- 188.125.64.7 2 6 17 1 +334us[+1012us] +/- 60ms
^+ 88.81.100.130 1 6 17 2 -173us[ +505us] +/- 22ms
^+ 2606:4700:f1::123 3 6 17 1 +334us[+1013us] +/- 18ms
^+ 2606:4700:f1::1 3 6 17 1 +555us[+1234us] +/- 18ms
EOF
else
echo "Failed"
fi

View File

@ -0,0 +1,29 @@
#/bin/sh
if [ "$1" = "-p" ] && [ "$2" = "-n" ]; then
cat<<EOF
remote refid st t when poll reach delay offset jitter
==============================================================================
0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 +0.000 0.000
2.rhel.pool.ntp .POOL. 16 p - 64 0 0.000 +0.000 0.000
+188.125.64.7 98.139.133.62 2 u 56 64 1 80.986 -10.248 20.809
-193.1.12.167 193.1.8.106 2 u 54 64 1 146.953 -20.845 14.280
-162.159.200.123 10.52.8.17 3 u 51 64 1 74.911 +18.266 20.879
*2a00:1288:110:f 31.60.135.175 2 u 54 64 1 35.304 -0.409 0.771
-2a00:1288:110:f 98.139.133.62 2 u 49 64 1 34.100 -0.069 0.503
-162.159.200.1 10.52.8.17 3 u 51 64 1 40.444 +1.681 10.464
+2606:4700:f1::1 10.215.8.4 3 u 52 64 1 18.389 -0.426 0.822
188.125.64.6 31.60.135.175 2 u 47 64 1 139.867 -19.354 24.647
2001:770:101:2: .GNSS. 1 u 62 64 1 35.393 +1.100 0.000
2001:770:101::2 .GNSS. 1 u 61 64 1 41.811 +3.700 0.000
88.81.100.130 .GPS. 1 u 48 64 1 66.919 -11.980 10.431
89.234.64.77 193.120.142.71 2 u 60 64 1 36.277 +0.195 0.000
85.91.1.164 193.120.10.3 2 u 57 64 1 148.037 -22.339 0.000
85.91.1.180 195.66.241.2 2 u 58 64 1 36.309 +0.183 0.000
EOF
else
echo "Failed"
fi