From ac05c575525e4729827c1a9b50b163b4272c862b Mon Sep 17 00:00:00 2001 From: qgarnier Date: Tue, 8 Feb 2022 10:10:19 +0100 Subject: [PATCH] (plugin) os::linux::local - ntp mode can check both ntp mode (#3470) --- os/linux/local/mode/ntp.pm | 241 +++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 114 deletions(-) diff --git a/os/linux/local/mode/ntp.pm b/os/linux/local/mode/ntp.pm index 88030faca..6fc62df15 100644 --- a/os/linux/local/mode/ntp.pm +++ b/os/linux/local/mode/ntp.pm @@ -79,39 +79,22 @@ sub custom_status_output { ); } -sub custom_status_calc { - my ($self, %options) = @_; - - $self->{result_values}->{rawtype} = $options{new_datas}->{$self->{instance} . '_type'}; - $self->{result_values}->{rawstate} = $options{new_datas}->{$self->{instance} . '_state'}; - if ($self->{instance_mode}->{command} eq 'ntpq') { - $self->{result_values}->{type} = $type_map_ntpq{$options{new_datas}->{$self->{instance} . '_type'}}; - } else { - $self->{result_values}->{type} = $type_map_chronyc{$options{new_datas}->{$self->{instance} . '_type'}}; - } - $self->{result_values}->{reach} = $options{new_datas}->{$self->{instance} . '_reach'}; - if ($self->{instance_mode}->{command} eq 'ntpq') { - $self->{result_values}->{state} = $state_map_ntpq{$options{new_datas}->{$self->{instance} . '_state'}}; - } else { - $self->{result_values}->{state} = $state_map_chronyc{$options{new_datas}->{$self->{instance} . '_state'}}; - } - return 0; -} - sub custom_offset_perfdata { my ($self, %options) = @_; if ($self->{result_values}->{state} ne '*') { $self->{output}->perfdata_add( - label => 'offset', unit => 'ms', - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + nlabel => $self->{nlabel}, + unit => 'ms', + instances => $self->{result_values}->{display}, value => $self->{result_values}->{offset}, min => 0 ); } else { $self->{output}->perfdata_add( - label => 'offset', unit => 'ms', - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + nlabel => $self->{nlabel}, + unit => 'ms', + instances => $self->{result_values}->{display}, value => $self->{result_values}->{offset}, warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), @@ -129,18 +112,24 @@ sub custom_offset_threshold { 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' } ]); } +sub prefix_peer_output { + my ($self, %options) = @_; + + return "Peer '" . $options{instance_value}->{display} . "' "; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ { name => 'global', type => 0 }, - { name => 'peers', type => 1, cb_prefix_output => 'prefix_peer_output', message_multiple => 'All peers are ok' }, + { name => 'peers', type => 1, cb_prefix_output => 'prefix_peer_output', message_multiple => 'All peers are ok' } ]; $self->{maps_counters}->{global} = [ - { label => 'peers', set => { + { label => 'peers', nlabel => 'peers.detected.count', set => { key_values => [ { name => 'peers' } ], - output_template => 'Number of ntp peers : %d', + output_template => 'Number of ntp peers: %d', perfdatas => [ { label => 'peers', template => '%d', min => 0 } ] @@ -150,26 +139,29 @@ sub set_counters { $self->{maps_counters}->{peers} = [ { label => 'status', type => 2, set => { - key_values => [ { name => 'state' }, { name => 'type' }, { name => 'reach' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_status_calc'), + key_values => [ + { name => 'rawstate' }, { name => 'rawtype' }, + { name => 'state' }, { name => 'type' }, + { name => 'reach' }, { name => 'display' } + ], closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => \&catalog_status_threshold_ng } }, - { label => 'offset', display_ok => 0, set => { + { label => 'offset', nlabel => 'peer.time.offset.milliseconds', display_ok => 0, set => { key_values => [ { name => 'offset' }, { name => 'state' }, { name => 'display' } ], - output_template => 'Offset : %s ms', + output_template => 'offset: %s ms', closure_custom_threshold_check => $self->can('custom_offset_threshold'), closure_custom_perfdata => $self->can('custom_offset_perfdata'), perfdatas => [ - { label => 'offset', template => '%s', min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display' } + { template => '%s', min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display' } ] } }, - { label => 'stratum', display_ok => 0, set => { + { label => 'stratum', nlabel => 'peer.stratum.count', display_ok => 0, set => { key_values => [ { name => 'stratum' }, { name => 'display' } ], - output_template => 'Stratum : %s', + output_template => 'stratum: %s', perfdatas => [ { label => 'stratum', template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } ] @@ -178,15 +170,9 @@ sub set_counters { ]; } -sub prefix_peer_output { - my ($self, %options) = @_; - - return "Peer '" . $options{instance_value}->{display} . "' "; -} - sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { @@ -202,84 +188,111 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if ($self->{option_results}->{ntp_mode} eq 'ntpq') { - $self->{regex} = '^(\+|\*|\.|\-|\#|x|\|o)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)'; - $self->{command} = 'ntpq'; - $self->{command_options} = '-p -n 2>&1'; - } elsif ($self->{option_results}->{ntp_mode} eq 'chronyc') { - $self->{regex} = '^(.)(\+|\*|\.|\-|\#|x|\)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*?)(\d+)(\w+)$'; - $self->{command} = 'chronyc'; - $self->{command_options} = '-n sources 2>&1'; - } else { + if ($self->{option_results}->{ntp_mode} !~ /^(?:ntpq|chronyc|all)$/) { $self->{output}->add_option_msg(short_msg => "ntp mode '" . $self->{option_results}->{ntp_mode} . "' not implemented" ); $self->{output}->option_exit(); - } + } +} + +sub get_ntp_modes { + my ($self, %options) = @_; + + my $modes = { + ntpq => { + regexp => '^(\+|\*|\.|\-|\#|x|\|o)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)', + command => 'ntpq', + command_options => '-p -n 2>&1', + type => 'ntpq' + }, + chronyc => { + regexp => '^(.)(\+|\*|\.|\-|\#|x|\)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*?)(\d+)(\w+)$', + command => 'chronyc', + command_options => '-n sources 2>&1', + type => 'chronyc' + } + }; + + if ($self->{option_results}->{ntp_mode} eq 'ntpq') { + return [ $modes->{ntpq} ]; + } elsif ($self->{option_results}->{ntp_mode} eq 'chronyc') { + return [ $modes->{chronyc} ]; + } + + return [ $modes->{chronyc}, $modes->{ntpq} ]; } sub manage_selection { my ($self, %options) = @_; - my ($stdout) = $options{custom}->execute_command( - command => $self->{command}, - command_options => $self->{command_options} - ); - + my $modes = $self->get_ntp_modes(); + $self->{global} = { peers => 0 }; $self->{peers} = {}; + foreach my $mode (@$modes) { + my ($stdout) = $options{custom}->execute_command( + command => $mode->{command}, + command_options => $mode->{command_options}, + no_quit => $self->{option_results}->{ntp_mode} eq 'all' ? 1 : undef + ); - my @lines = split /\n/, $stdout; - foreach my $line (@lines) { - if ($line =~ /Connection refused/) { - $self->{output}->add_option_msg(short_msg => "check ntp.conf and ntp daemon" ); - $self->{output}->option_exit(); - } - next if ($line !~ /$self->{regex}/); - - my ($remote_peer, $peer_fate) = (centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($1)); - if ($self->{command} eq 'chronyc') { - $remote_peer = centreon::plugins::misc::trim($3); - $peer_fate = centreon::plugins::misc::trim($2); - } - if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && - $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 ($self->{command} eq 'ntpq') { - my ($refid, $stratum, $type, $last_time, $polling_intervall, $reach, $delay, $offset, $jitter) = ($3, $4, $5, $6, $7, $8, $9, $10, $11); - $self->{peers}->{$remote_peer} = { - display => $remote_peer, - state => $peer_fate, - stratum => centreon::plugins::misc::trim($stratum), - type => centreon::plugins::misc::trim($type), - reach => centreon::plugins::misc::trim($reach), - offset => centreon::plugins::misc::trim($offset) - }; - } elsif ($self->{command} eq 'chronyc') { - #210 Number of sources = 4 - #MS Name/IP address Stratum Poll Reach LastRx Last sample - #=============================================================================== - #^+ 212.83.187.62 2 9 377 179 -715us[ -731us] +/- 50ms - #^- 129.250.35.251 2 8 377 15 -82us[ -99us] +/- 96ms + my @lines = split(/\n/, $stdout); + foreach my $line (@lines) { + if ($self->{option_results}->{ntp_mode} ne 'all' && $line =~ /Connection refused/) { + $self->{output}->add_option_msg(short_msg => "check ntp.conf and ntp daemon" ); + $self->{output}->option_exit(); + } + next if ($line !~ /$mode->{regexp}/); - my ($type, $stratum, $poll, $reach, $lastRX, $offset) = ($1, $4, $5, $6, $7, $9); - $self->{peers}->{$remote_peer} = { - display => $remote_peer, - state => $peer_fate, - stratum => centreon::plugins::misc::trim($stratum), - type => centreon::plugins::misc::trim($type), - reach => centreon::plugins::misc::trim($reach), - offset => centreon::plugins::misc::trim($offset) * $unit_map_chronyc{centreon::plugins::misc::trim($10)}, - }; + my ($remote_peer, $peer_fate) = (centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($1)); + if ($mode->{type} eq 'chronyc') { + $remote_peer = centreon::plugins::misc::trim($3); + $peer_fate = centreon::plugins::misc::trim($2); + } + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $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') { + my ($refid, $stratum, $type, $last_time, $polling_intervall, $reach, $delay, $offset, $jitter) = ($3, $4, $5, $6, $7, $8, $9, $10, $11); + $self->{peers}->{$remote_peer} = { + display => $remote_peer, + rawstate => $peer_fate, + state => $state_map_ntpq{$peer_fate}, + stratum => centreon::plugins::misc::trim($stratum), + rawtype => centreon::plugins::misc::trim($type), + type => $type_map_ntpq{centreon::plugins::misc::trim($type)}, + reach => centreon::plugins::misc::trim($reach), + offset => centreon::plugins::misc::trim($offset) + }; + } elsif ($mode->{type} eq 'chronyc') { + #210 Number of sources = 4 + #MS Name/IP address Stratum Poll Reach LastRx Last sample + #=============================================================================== + #^+ 212.83.187.62 2 9 377 179 -715us[ -731us] +/- 50ms + #^- 129.250.35.251 2 8 377 15 -82us[ -99us] +/- 96ms + + my ($type, $stratum, $poll, $reach, $lastRX, $offset) = ($1, $4, $5, $6, $7, $9); + $self->{peers}->{$remote_peer} = { + display => $remote_peer, + rawstate => $peer_fate, + state => $state_map_chronyc{$peer_fate}, + stratum => centreon::plugins::misc::trim($stratum), + rawtype => centreon::plugins::misc::trim($type), + type => $type_map_chronyc{centreon::plugins::misc::trim($type)}, + reach => centreon::plugins::misc::trim($reach), + offset => centreon::plugins::misc::trim($offset) * $unit_map_chronyc{centreon::plugins::misc::trim($10)}, + }; + } + + $self->{global}->{peers}++; } - - $self->{global}->{peers}++; } } @@ -297,7 +310,7 @@ Command used: 'ntpq -p -n 2>&1' or 'chronyc -n sources 2>&1' =item B<--ntp-mode> -Default mode for parsing and command: 'ntpq' (default) or 'chronyc'. +Default mode for parsing and command: 'ntpq' (default), 'chronyc' or 'all'. =item B<--filter-name> @@ -309,19 +322,19 @@ Filter peer state (can be a regexp). =item B<--warning-peers> -Threshold warning minimum Amount of NTP-Server +Threshold warning minimum amount of NTP-Server =item B<--critical-peers> -Threshold critical minimum Amount of NTP-Server +Threshold critical minimum amount of NTP-Server =item B<--warning-offset> -Threshold warning Offset deviation value in milliseconds +Threshold warning offset deviation value in milliseconds =item B<--critical-offset> -Threshold critical Offset deviation value in milliseconds +Threshold critical offset deviation value in milliseconds =item B<--warning-stratum> @@ -333,17 +346,17 @@ Threshold critical. =item B<--unknown-status> -Set warning threshold for status (Default: ''). +Set unknown threshold for status. Can used special variables like: %{state}, %{rawstate}, %{type}, %{rawtype}, %{reach}, %{display} =item B<--warning-status> -Set warning threshold for status (Default: ''). +Set warning threshold for status. Can used special variables like: %{state}, %{rawstate}, %{type}, %{rawtype}, %{reach}, %{display} =item B<--critical-status> -Set critical threshold for status (Default: ''). +Set critical threshold for status. Can used special variables like: %{state}, %{rawstate}, %{type}, %{rawtype}, %{reach}, %{display} =back