From c965706bee55100d04c742ea1cd579eff10e35bb Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Thu, 2 Apr 2020 16:31:23 +0200 Subject: [PATCH] break change: refacto hddtemp plugin --- centreon-plugins/apps/hddtemp/custom/cli.pm | 264 ++++++++++++++++++ centreon-plugins/apps/hddtemp/custom/tcp.pm | 198 +++++++++++++ .../apps/hddtemp/local/mode/temperature.pm | 184 ------------ centreon-plugins/apps/hddtemp/local/plugin.pm | 48 ---- .../apps/hddtemp/mode/listdrives.pm | 97 +++++++ .../apps/hddtemp/mode/temperatures.pm | 169 +++++++++++ .../apps/hddtemp/{remote => }/plugin.pm | 17 +- .../apps/hddtemp/remote/mode/listdrives.pm | 160 ----------- .../apps/hddtemp/remote/mode/temperature.pm | 210 -------------- .../centreon/plugins/backend/ssh/libssh.pm | 2 +- .../centreon/plugins/backend/ssh/plink.pm | 3 +- .../centreon/plugins/backend/ssh/sshcli.pm | 3 +- 12 files changed, 744 insertions(+), 611 deletions(-) create mode 100644 centreon-plugins/apps/hddtemp/custom/cli.pm create mode 100644 centreon-plugins/apps/hddtemp/custom/tcp.pm delete mode 100644 centreon-plugins/apps/hddtemp/local/mode/temperature.pm delete mode 100644 centreon-plugins/apps/hddtemp/local/plugin.pm create mode 100644 centreon-plugins/apps/hddtemp/mode/listdrives.pm create mode 100644 centreon-plugins/apps/hddtemp/mode/temperatures.pm rename centreon-plugins/apps/hddtemp/{remote => }/plugin.pm (65%) delete mode 100644 centreon-plugins/apps/hddtemp/remote/mode/listdrives.pm delete mode 100644 centreon-plugins/apps/hddtemp/remote/mode/temperature.pm diff --git a/centreon-plugins/apps/hddtemp/custom/cli.pm b/centreon-plugins/apps/hddtemp/custom/cli.pm new file mode 100644 index 000000000..9df6ecfc4 --- /dev/null +++ b/centreon-plugins/apps/hddtemp/custom/cli.pm @@ -0,0 +1,264 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::hddtemp::custom::cli; + +use strict; +use warnings; +use centreon::plugins::ssh; +use centreon::plugins::misc; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname' }, + 'timeout:s' => { name => 'timeout', default => 45 }, + 'command-drives:s' => { name => 'command_drives' }, + 'command-path-drives:s' => { name => 'command_path_drives' }, + 'command-options-drives:s' => { name => 'command_options_drives' }, + 'command-hddtemp:s' => { name => 'command_hddtemp' }, + 'command-path-hddtemp:s' => { name => 'command_path_hddtemp' }, + 'command-options-hddtemp:s' => { name => 'command_options_hddtemp' }, + 'sudo:s' => { name => 'sudo' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'CLI OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{mode} = $options{mode}; + $self->{ssh} = centreon::plugins::ssh->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults { + my ($self, %options) = @_; + + foreach (keys %{$options{default}}) { + if ($_ eq $self->{mode}) { + for (my $i = 0; $i < scalar(@{$options{default}->{$_}}); $i++) { + foreach my $opt (keys %{$options{default}->{$_}[$i]}) { + if (!defined($self->{option_results}->{$opt}[$i])) { + $self->{option_results}->{$opt}[$i] = $options{default}->{$_}[$i]->{$opt}; + } + } + } + } + } +} + +sub check_options { + my ($self, %options) = @_; + + if (defined($self->{option_results}->{hostname}) && $self->{option_results}->{hostname} ne '') { + $self->{ssh}->check_options(option_results => $self->{option_results}); + } + + return 0; +} + +sub list_drives { + my ($self, %options) = @_; + + my $stdout; + if (defined($self->{option_results}->{hostname}) && $self->{option_results}->{hostname} ne '') { + ($stdout) = $self->{ssh}->execute( + hostname => $self->{option_results}->{hostname}, + command => defined($self->{option_results}->{command_drives}) && $self->{option_results}->{command_drives} ne '' ? $self->{option_results}->{command_drives} : 'lsblk', + command_path => $self->{option_results}->{command_path_drives}, + command_options => defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options_drives} ne '' ? $self->{option_results}->{command_options_drives} : '-I 8 -d -o NAME -p -n', + timeout => $self->{option_results}->{timeout} + ); + } else { + ($stdout) = centreon::plugins::misc::execute( + output => $self->{output}, + options => { timeout => $self->{option_results}->{timeout} }, + command => defined($self->{option_results}->{command_drives}) && $self->{option_results}->{command_drives} ne '' ? $self->{option_results}->{command_drives} : 'lsblk', + command_path => $self->{option_results}->{command_path_drives}, + command_options => defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options_drives} ne '' ? $self->{option_results}->{command_options_drives} : '-I 8 -d -o NAME -p -n' + ); + } + + $self->{output}->output_add(long_msg => "command response: $stdout", debug => 1); + my $drives = {}; + $drives->{$_} = {} foreach (split /\n/, $stdout); + + return $drives; +} + +sub get_drives_information { + my ($self, %options) = @_; + + my $drives = $self->list_drives(); + my $cmd_options = '-u C ' . join(' ', keys %$drives); + + my ($stdout, $exit_code); + if (defined($self->{option_results}->{hostname}) && $self->{option_results}->{hostname} ne '') { + ($stdout, $exit_code) = $self->{ssh}->execute( + hostname => $self->{option_results}->{hostname}, + sudo => $self->{option_results}->{sudo}, + command => defined($self->{option_results}->{command_hddtemp}) && $self->{option_results}->{command_hddtemp} ne '' ? $self->{option_results}->{command_hddtemp} : 'hddtemp', + command_path => $self->{option_results}->{command_path_hddtemp}, + command_options => defined($self->{option_results}->{command_options_hddtemp}) && $self->{option_results}->{command_options_hddtemp} ne '' ? $self->{option_results}->{command_options_hddtemp} : $cmd_options, + timeout => $self->{option_results}->{timeout}, + no_quit => 1 + ); + } else { + ($stdout, $exit_code) = centreon::plugins::misc::execute( + output => $self->{output}, + options => { timeout => $self->{option_results}->{timeout} }, + sudo => $self->{option_results}->{sudo}, + command => defined($self->{option_results}->{command_hddtemp}) && $self->{option_results}->{command_hddtemp} ne '' ? $self->{option_results}->{command_hddtemp} : 'hddtemp', + command_path => $self->{option_results}->{command_path_hddtemp}, + command_options => defined($self->{option_results}->{command_options_hddtemp}) && $self->{option_results}->{command_options_hddtemp} ne '' ? $self->{option_results}->{command_options_hddtemp} : $cmd_options . ' 2> /dev/null', + no_quit => 1, + ); + } + + # exit values can be: 0/1. Need root permissions. + if ($exit_code != 0 && $exit_code != 1) { + $self->{output}->add_option_msg(short_msg => sprintf('command execution error [exit code: %s]', $exit_code)); + $self->{output}->option_exit(); + } + + # OK: + # /dev/sda: SanDisk ...: 32 C + # ERROR: + # message on stderr. So if we don't catch stderr and we have nothing, surely error. for example: + # /dev/sda: open: Permission denied + # UNKNOWN: + # /dev/sda: SanDisk ...: no sensor + # SLEEP: + # /dev/sda: SanDisk ...: drive is sleeping + # NOSENSOR: + # /dev/sda: SanDisk ...: drive supported, but it doesn't have a temperature sensor + # NOT_APPLICABLE: + # /dev/sda: SanDisk ...: misc message + foreach my $name (keys %$drives) { + if ($stdout =~ /^$name:.*?:\s+(\d+).*?C/m) { + $drives->{$name}->{status} = 'ok'; + $drives->{$name}->{temperature_unit} = 'C'; + $drives->{$name}->{temperature} = $1; + } elsif ($stdout =~ /^$name:.*?:\s+(.*)$/m) { + my $message = $1; + $drives->{$name}->{status} = 'notApplicable'; + $drives->{$name}->{status} = 'unknown' if ($message =~ /no sensor/i); + $drives->{$name}->{status} = 'driveSleep' if ($message =~ /drive is sleeping/i); + $drives->{$name}->{status} = 'noSensor' if ($message =~ /drive supported, but it doesn't have a temperature sensor/i); + } else { + $drives->{$name}->{status} = 'error'; + } + } + + return $drives; +} + +1; + +__END__ + +=head1 NAME + +ssh + +=head1 SYNOPSIS + +my ssh + +=head1 CLI OPTIONS + +=over 8 + +=item B<--hostname> + +Hostname to query (ssh mode). + +=item B<--timeout> + +Timeout in seconds for the command (Default: 45). + +=item You can override command for drives listing. +By default, we use 'lsblk -I 8 -d -o NAME -p -n': + +=over 16 + +=item B<--command-drives> + +Command to get information. Used it you have output in a file. + +=item B<--command-path-drives> + +Command path. + +=item B<--command-options-drives> + +Command options. + +=back + +=item You can override command hddtemp used. +By default, we use 'hddtemp -u C /dev/sda /dev/sdb ...' built with the result of drives command: + +=over 16 + +=item B<--command-hddtemp> + +Command to get information. Used it you have output in a file. + +=item B<--command-path-hddtemp> + +Command path. + +=item B<--command-options-hddtemp> + +Command options. + +=item B<--sudo> + +Sudo hddtemp command. + +=back + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/centreon-plugins/apps/hddtemp/custom/tcp.pm b/centreon-plugins/apps/hddtemp/custom/tcp.pm new file mode 100644 index 000000000..532026900 --- /dev/null +++ b/centreon-plugins/apps/hddtemp/custom/tcp.pm @@ -0,0 +1,198 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::hddtemp::custom::tcp; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use IO::Socket; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port' }, + 'timeout:s' => { name => 'timeout' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'CUSTOM TCP OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{mode} = $options{mode}; + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults { + my ($self, %options) = @_; + + foreach (keys %{$options{default}}) { + if ($_ eq $self->{mode}) { + for (my $i = 0; $i < scalar(@{$options{default}->{$_}}); $i++) { + foreach my $opt (keys %{$options{default}->{$_}[$i]}) { + if (!defined($self->{option_results}->{$opt}[$i])) { + $self->{option_results}->{$opt}[$i] = $options{default}->{$_}[$i]->{$opt}; + } + } + } + } + } +} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{port} = (defined($self->{option_results}->{port})) && $self->{option_results}->{port} =~ /(\d+)/ ? $1 : 7634; + $self->{timeout} = (defined($self->{option_results}->{timeout})) && $self->{option_results}->{timeout} =~ /(\d+)/ ? $1 : 30; + + if ($self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => 'Need to specify --hostname option.'); + $self->{output}->option_exit(); + } + + return 0; +} + +sub get_hddtemp_drives { + my ($self, %options) = @_; + + my $socket = new IO::Socket::INET( + Proto => 'tcp', + PeerAddr => $self->{hostname}, + PeerPort => $self->{port}, + Timeout => $self->{timeout} + ); + + if (!defined($socket)) { + $self->{output}->add_option_msg(short_msg => "could not connect: $@"); + $self->{output}->option_exit(); + } + + my $line; + eval { + local $SIG{ALRM} = sub { die 'Timeout'; }; + alarm($self->{timeout}); + $line = <$socket>; + alarm(0); + }; + $socket->shutdown(2); + if ($@) { + $self->{output}->add_option_msg(short_msg => 'cannot get informations: ' . $@); + $self->{output}->option_exit(); + } + + return $line; +} + +sub list_drives { + my ($self, %options) = @_; + + my $line = $self->get_hddtemp_drives(); + my $drives = {}; + while ($line =~ /\|(.*?)\|(.*?)\|(.*?)\|(.*?)\|/msg) { + $drives->{$1} = {}; + } + + return $drives; +} + +sub get_drives_information { + my ($self, %options) = @_; + + my $line = $self->get_hddtemp_drives(); + + #|/dev/sda|SanDisk ....|33|C| + #|/dev/sda|Scan .... |NA|*| + my $mapping_errors = { + NA => 'notApplicable', + UNK => 'unknown', + NOS => 'noSensor', + SLP => 'driveSleep', + ERR => 'error' + }; + + my $drives = {}; + while ($line =~ /\|(.*?)\|(.*?)\|(.*?)\|(.*?)\|/msg) { + my ($name, $value, $unit) = ($1, $3, $4); + if ($value =~ /\d+/) { + $drives->{$name} = { temperature => $value, temperature_unit => $unit, status => 'ok' }; + } else { + $drives->{$name} = { status => $mapping_errors->{$value} }; + } + } + + return $drives; +} + +1; + +__END__ + +=head1 NAME + +Hddtemp + +=head1 CUSTOM TCP OPTIONS + +Hddtemp tcp + +=over 8 + +=item B<--hostname> + +Hostname or IP address. + +=item B<--port> + +Port used (Default: 7634) + +=item B<--timeout> + +Set timeout in seconds (Default: 30). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/centreon-plugins/apps/hddtemp/local/mode/temperature.pm b/centreon-plugins/apps/hddtemp/local/mode/temperature.pm deleted file mode 100644 index 06091f8a6..000000000 --- a/centreon-plugins/apps/hddtemp/local/mode/temperature.pm +++ /dev/null @@ -1,184 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package apps::hddtemp::local::mode::temperature; - -use base qw(centreon::plugins::mode); - -use strict; -use warnings; -use centreon::plugins::misc; - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $options{options}->add_options(arguments => - { - "hostname:s" => { name => 'hostname' }, - "remote" => { name => 'remote' }, - "ssh-option:s@" => { name => 'ssh_option' }, - "ssh-path:s" => { name => 'ssh_path' }, - "ssh-command:s" => { name => 'ssh_command', default => 'ssh' }, - "timeout:s" => { name => 'timeout', default => 30 }, - "sudo" => { name => 'sudo' }, - "command:s" => { name => 'command', default => 'hddtemp' }, - "command-path:s" => { name => 'command_path', default => '/usr/sbin' }, - "command-options:s" => { name => 'command_options', default => '-u' }, - "warning:s" => { name => 'warning' }, - "critical:s" => { name => 'critical' }, - "disks:s" => { name => 'disks' }, - "unit:s" => { name => 'unit', default => 'C' } - }); - - return $self; -} - -sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); - - if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{warning} . "'."); - $self->{output}->option_exit(); - } - if (($self->{perfdata}->threshold_validate(label => 'critical', value => $self->{option_results}->{critical})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{critical} . "'."); - $self->{output}->option_exit(); - } - if (!defined($self->{option_results}->{disks}) || $self->{option_results}->{disks} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify hdd (ex. /dev/sda)."); - $self->{output}->option_exit(); - } - - #### Create command_options - if (defined($self->{option_results}->{unit})) { - $self->{option_results}->{command_options} .= $self->{option_results}->{unit}; - } - $self->{option_results}->{command_options} .= ' ' . $self->{option_results}->{disks}; - $self->{option_results}->{command_options} .= ' 2>&1'; -} - -sub run { - my ($self, %options) = @_; - my $total_size = 0; - - my $stdout = centreon::plugins::misc::execute(output => $self->{output}, - options => $self->{option_results}, - sudo => $self->{option_results}->{sudo}, - command => $self->{option_results}->{command}, - command_path => $self->{option_results}->{command_path}, - command_options => $self->{option_results}->{command_options}); - - $self->{output}->output_add(severity => 'OK', - short_msg => "All temperatures are ok."); - foreach (split(/\n/, $stdout)) { - next if (!/(.*): (.*): ([0-9]*)/); - my ($disk, $model, $temp) = ($1, $2, $3); - - my $exit_code = $self->{perfdata}->threshold_check(value => $temp, - threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(long_msg => sprintf("%s: %s", $disk, $temp . '°' . $self->{option_results}->{unit})); - if (!$self->{output}->is_status(litteral => 1, value => $exit_code, compare => 'ok')) { - $self->{output}->output_add(severity => $exit_code, - short_msg => sprintf("'%s' temp is %s", $disk, $temp . '°' . $self->{option_results}->{unit})); - } - $self->{output}->perfdata_add(label => $disk, unit => $self->{option_results}->{unit}, - value => $temp, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => 0); - } - - $self->{output}->display(); - $self->{output}->exit(); -} - -1; - -__END__ - -=head1 MODE - -Check hdd temperature with hddtemp. - -=over 8 - -=item B<--disks> - -Disks to check (ex: /dev/sda) - -=item B<--unit> - -Temperature unit (default: C). - -=item B<--warning> - -Threshold warning in °. - -=item B<--critical> - -Threshold critical in °. - -=item B<--remote> - -Execute command remotely in 'ssh'. - -=item B<--hostname> - -Hostname to query (need --remote). - -=item B<--ssh-option> - -Specify multiple options like the user (example: --ssh-option='-l=centreon-engine' --ssh-option='-p=52'). - -=item B<--ssh-path> - -Specify ssh command path (default: none) - -=item B<--ssh-command> - -Specify ssh command (default: 'ssh'). Useful to use 'plink'. - -=item B<--timeout> - -Timeout in seconds for the command (Default: 30). - -=item B<--sudo> - -Use 'sudo' to execute the command. - -=item B<--command> - -Command to get information (Default: 'hddtemp'). -Can be changed if you have output in a file. - -=item B<--command-path> - -Command path (Default: '/usr/sbin'). - -=item B<--command-options> - -Command options (Default: '-u'). - -=back - -=cut diff --git a/centreon-plugins/apps/hddtemp/local/plugin.pm b/centreon-plugins/apps/hddtemp/local/plugin.pm deleted file mode 100644 index ff84f189a..000000000 --- a/centreon-plugins/apps/hddtemp/local/plugin.pm +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package apps::hddtemp::local::plugin; - -use strict; -use warnings; -use base qw(centreon::plugins::script_simple); - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $self->{version} = '0.1'; - %{$self->{modes}} = ( - 'temperature' => 'apps::hddtemp::local::mode::temperature', - ); - - return $self; -} - -1; - -__END__ - -=head1 PLUGIN DESCRIPTION - -Check Linux through local commands (the plugin can use SSH). - -=cut diff --git a/centreon-plugins/apps/hddtemp/mode/listdrives.pm b/centreon-plugins/apps/hddtemp/mode/listdrives.pm new file mode 100644 index 000000000..b91957926 --- /dev/null +++ b/centreon-plugins/apps/hddtemp/mode/listdrives.pm @@ -0,0 +1,97 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::hddtemp::mode::listdrives; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + return $options{custom}->list_drives(); +} + +sub run { + my ($self, %options) = @_; + + my $drives = $self->manage_selection(%options); + foreach (sort keys %$drives) { + $self->{output}->output_add(long_msg => + sprintf( + '[name = %s]', + $_ + ) + ); + } + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List drives:' + ); + + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => ['name']); +} + +sub disco_show { + my ($self, %options) = @_; + + my $drives = $self->manage_selection(%options); + foreach (sort keys %$drives) { + $self->{output}->add_disco_entry(name => $_); + } +} + +1; + +__END__ + +=head1 MODE + +List queues. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/apps/hddtemp/mode/temperatures.pm b/centreon-plugins/apps/hddtemp/mode/temperatures.pm new file mode 100644 index 000000000..61f2e2d77 --- /dev/null +++ b/centreon-plugins/apps/hddtemp/mode/temperatures.pm @@ -0,0 +1,169 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::hddtemp::mode::temperatures; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold catalog_status_calc); + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf( + 'status: %s', + $self->{result_values}->{status}, + ); +} + +sub custom_temperature_output { + my ($self, %options) = @_; + + return sprintf('temperature: %s %s', + $self->{result_values}->{temperature_absolute}, + $self->{result_values}->{temperature_unit_absolute} + ); +} + +sub custom_temperature_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => 'drive.temperature.' . ($self->{result_values}->{temperature_unit_absolute} eq 'C' ? 'celsius' : 'fahrenheit'), + instances => $self->{result_values}->{display_absolute}, + unit => $self->{result_values}->{temperature_unit_absolute}, + value => $self->{result_values}->{temperature_absolute}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + ); +} + +sub prefix_drive_output { + my ($self, %options) = @_; + + return "Drive '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'drives', type => 1, cb_prefix_output => 'prefix_drive_output', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{drives} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'status' }, { name => 'display' } ], + closure_custom_calc => \&catalog_status_calc, + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold + } + }, + { label => 'temperature', set => { + key_values => [ { name => 'temperature' }, { name => 'temperature_unit' }, { name => 'display' } ], + closure_custom_output => $self->can('custom_temperature_output'), + closure_custom_perfdata => $self->can('custom_temperature_perfdata') + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'filter-name:s' => { name => 'filter_name' }, + 'unknown-status:s' => { name => 'unknown_status', default => '' }, + 'warning-status:s' => { name => 'warning_status', default => '' }, + 'critical-status:s' => { name => 'critical_status', default => '%{status} !~ /ok/i' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['unknown_status', 'warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->get_drives_information(); + + $self->{drives} = {}; + foreach (keys %$results) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $_ !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping drive '" . $_ . "': no matching filter.", debug => 1); + next; + } + + $self->{drives}->{$_} = { + display => $_, + %{$results->{$_}} + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check drive temperatures. + +=over 8 + +=item B<--filter-name> + +Filter drive name (Can use regexp). + +=item B<--unknown-status> + +Set unknown threshold for status. +Can used special variables like: %{status}, %{display} + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{display} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} !~ /ok/i'). +Can used special variables like: %{status}, %{display} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'temperature'. + +=back + +=cut diff --git a/centreon-plugins/apps/hddtemp/remote/plugin.pm b/centreon-plugins/apps/hddtemp/plugin.pm similarity index 65% rename from centreon-plugins/apps/hddtemp/remote/plugin.pm rename to centreon-plugins/apps/hddtemp/plugin.pm index 57b0fb743..2a1a0c83f 100644 --- a/centreon-plugins/apps/hddtemp/remote/plugin.pm +++ b/centreon-plugins/apps/hddtemp/plugin.pm @@ -18,23 +18,25 @@ # limitations under the License. # -package apps::hddtemp::remote::plugin; +package apps::hddtemp::plugin; use strict; use warnings; -use base qw(centreon::plugins::script_simple); +use base qw(centreon::plugins::script_custom); sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $self->{version} = '0.1'; + $self->{version} = '1.0'; %{$self->{modes}} = ( - 'temperature' => 'apps::hddtemp::remote::mode::temperature', - 'list-drives' => 'apps::hddtemp::remote::mode::listdrives', + 'list-drives' => 'apps::hddtemp::mode::listdrives', + 'temperatures' => 'apps::hddtemp::mode::temperatures' ); + $self->{custom_modes}{tcp} = 'apps::hddtemp::custom::tcp'; + $self->{custom_modes}{cli} = 'apps::hddtemp::custom::cli'; return $self; } @@ -44,6 +46,9 @@ __END__ =head1 PLUGIN DESCRIPTION -Check HDDTEMP Status throuh TCP Socket +Check drives temperature with hddtemp. +Two custom modes availables: +'tcp' (remotely with hddtemp in daemon mode) +'command' (with hddtemp command. you can execute locally or through ssh). =cut diff --git a/centreon-plugins/apps/hddtemp/remote/mode/listdrives.pm b/centreon-plugins/apps/hddtemp/remote/mode/listdrives.pm deleted file mode 100644 index f9ae7e492..000000000 --- a/centreon-plugins/apps/hddtemp/remote/mode/listdrives.pm +++ /dev/null @@ -1,160 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package apps::hddtemp::remote::mode::listdrives; - -use base qw(centreon::plugins::mode); - -use strict; -use warnings; -use IO::Socket; - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $options{options}->add_options(arguments => - { - "hostname:s" => { name => 'hostname' }, - "port:s" => { name => 'port', default => '7634' }, - "timeout:s" => { name => 'timeout', default => '10' }, - "filter-name:s" => { name => 'filter_name', }, - }); - - $self->{result} = {}; - $self->{hostname} = undef; - return $self; -} - -sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); - - if (!defined($self->{option_results}->{hostname})) { - $self->{output}->add_option_msg(short_msg => "Please set the hostname option"); - $self->{output}->option_exit(); - } - -} - -sub manage_selection { - my ($self, %options) = @_; - - my $oSocketConn = new IO::Socket::INET ( Proto => 'tcp', - PeerAddr => $self->{option_results}->{hostname}, - PeerPort => $self->{option_results}->{port}, - Timeout => $self->{option_results}->{timeout}, - ); - - if (!defined($oSocketConn)) { - $self->{output}->add_option_msg(short_msg => "Could not connect."); - $self->{output}->option_exit(); - } - - #|/dev/sda|SD280813AS|35|C|#|/dev/sdb|ST2000CD005-1CH134|35|C| - - my $line; - - eval { - local $SIG{ALRM} = sub { die "Timeout by signal ALARM\n"; }; - alarm(10); - $line = <$oSocketConn>; - alarm(0); - }; - $oSocketConn->shutdown(2); - if ($@) { - $self->{output}->add_option_msg(short_msg => "Cannot get informations."); - $self->{output}->option_exit(); - } - - while ($line =~ /\|([^|]+)\|([^|]+)\|([^|]+)\|(C|F)\|/g) { - my ($drive, $serial, $temperature, $unit) = ($1, $2, $3, $4); - - if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && - $drive !~ /$self->{option_results}->{filter_name}/) { - $self->{output}->output_add(long_msg => "Skipping drive '" . $drive . "': no matching filter name"); - next; - } - - $self->{result}->{$drive} = {serial => $serial, temperature => $temperature, unit => $unit}; - } -} - -sub run { - my ($self, %options) = @_; - - $self->manage_selection(); - foreach my $name (sort(keys %{$self->{result}})) { - $self->{output}->output_add(long_msg => "'" . $name . "' [temperature = " . $self->{result}->{$name}->{temperature} . $self->{result}->{$name}->{unit} . ']'); - } - - $self->{output}->output_add(severity => 'OK', - short_msg => 'List Drives:'); - $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); - $self->{output}->exit(); -} - -sub disco_format { - my ($self, %options) = @_; - - $self->{output}->add_disco_format(elements => ['name', 'temperature']); -} - -sub disco_show { - my ($self, %options) = @_; - - $self->manage_selection(); - foreach my $name (sort(keys %{$self->{result}})) { - $self->{output}->add_disco_entry(name => $name, - temperature => $self->{result}->{$name}->{temperature} - ); - } -} - -1; - -__END__ - -=head1 MODE - -List HDDTEMP Harddrives - -=over 8 - -=item B<--hostname> - -IP Address or FQDN of the Server - -=item B<--port> - -Port used by Hddtemp (Default: 7634) - -=item B<--timeout> - -Set Timeout for Socketconnect - -=item B<--filter-name> - -Filter Harddrive name (regexp can be used). - -=back - -=cut diff --git a/centreon-plugins/apps/hddtemp/remote/mode/temperature.pm b/centreon-plugins/apps/hddtemp/remote/mode/temperature.pm deleted file mode 100644 index 0e837c94c..000000000 --- a/centreon-plugins/apps/hddtemp/remote/mode/temperature.pm +++ /dev/null @@ -1,210 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package apps::hddtemp::remote::mode::temperature; - -use base qw(centreon::plugins::mode); - -use strict; -use warnings; -use IO::Socket; - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $options{options}->add_options(arguments => { - "hostname:s" => { name => 'hostname' }, - "port:s" => { name => 'port', default => '7634' }, - "timeout:s" => { name => 'timeout', default => '10' }, - "name:s" => { name => 'name' }, - "warning:s" => { name => 'warning' }, - "critical:s" => { name => 'critical' }, - "regexp" => { name => 'use_regexp' }, - "regexp-isensitive" => { name => 'use_regexpi' }, - }); - - $self->{result} = {}; - $self->{hostname} = undef; - return $self; -} - -sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); - - if (!defined($self->{option_results}->{hostname})) { - $self->{output}->add_option_msg(short_msg => "Please set the hostname option"); - $self->{output}->option_exit(); - } - if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); - $self->{output}->option_exit(); - } - if (($self->{perfdata}->threshold_validate(label => 'critical', value => $self->{option_results}->{critical})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{option_results}->{critical} . "'."); - $self->{output}->option_exit(); - } - -} - -sub manage_selection { - my ($self, %options) = @_; - - my $oSocketConn = new IO::Socket::INET ( - Proto => 'tcp', - PeerAddr => $self->{option_results}->{hostname}, - PeerPort => $self->{option_results}->{port}, - Timeout => $self->{option_results}->{timeout}, - ); - - if (!defined($oSocketConn)) { - $self->{output}->add_option_msg(short_msg => "Could not connect."); - $self->{output}->option_exit(); - } - - #|/dev/sda|SD280813AS|35|C|#|/dev/sdb|ST2000CD005-1CH134|35|C| - - my $line; - - eval { - local $SIG{ALRM} = sub { die "Timeout by signal ALARM\n"; }; - alarm(10); - $line = <$oSocketConn>; - alarm(0); - }; - $oSocketConn->shutdown(2); - if ($@) { - $self->{output}->add_option_msg(short_msg => "Cannot get informations."); - $self->{output}->option_exit(); - } - - while ($line =~ /\|([^|]+)\|([^|]+)\|([^|]+)\|(C|F)\|/g) { - my ($drive, $serial, $temperature, $unit) = ($1, $2, $3, $4); - - next if (defined($self->{option_results}->{name}) && defined($self->{option_results}->{use_regexp}) && defined($self->{option_results}->{use_regexpi}) - && $drive !~ /$self->{option_results}->{name}/i); - next if (defined($self->{option_results}->{name}) && defined($self->{option_results}->{use_regexp}) && !defined($self->{option_results}->{use_regexpi}) - && $drive !~ /$self->{option_results}->{name}/); - next if (defined($self->{option_results}->{name}) && !defined($self->{option_results}->{use_regexp}) && !defined($self->{option_results}->{use_regexpi}) - && $drive ne $self->{option_results}->{name}); - - $self->{result}->{$drive} = {serial => $serial, temperature => $temperature, unit => $unit}; - } - - if (scalar(keys %{$self->{result}}) <= 0) { - if (defined($self->{option_results}->{name})) { - $self->{output}->add_option_msg(short_msg => "No drives found for name '" . $self->{option_results}->{name} . "'."); - } else { - $self->{output}->add_option_msg(short_msg => "No drives found."); - } - $self->{output}->option_exit(); - } - -} - -sub run { - my ($self, %options) = @_; - - $self->manage_selection(); - - if (!defined($self->{option_results}->{name}) || defined($self->{option_results}->{use_regexp})) { - $self->{output}->output_add(severity => 'OK', - short_msg => 'All Harddrive Temperatures are ok.'); - }; - - foreach my $name (sort(keys %{$self->{result}})) { - my $exit = $self->{perfdata}->threshold_check(value => $self->{result}->{$name}->{temperature}, threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - - $self->{output}->output_add(long_msg => sprintf("Harddrive '%s' Temperature : %s%s", - $name, - $self->{result}->{$name}->{temperature}, - $self->{result}->{$name}->{unit})); - if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1) || (defined($self->{option_results}->{name}) && !defined($self->{option_results}->{use_regexp}))) { - $self->{output}->output_add(severity => $exit, - short_msg => sprintf("Harddrive '%s' Temperature : %s%s", - $name, - $self->{result}->{$name}->{temperature}, - $self->{result}->{$name}->{unit})); - } - - my $extra_label; - $extra_label = '_' . $name if (!defined($self->{option_results}->{name}) || defined($self->{option_results}->{use_regexp})); - $self->{output}->perfdata_add( - label => 'temp', - intances => $extra_label, - unit => $self->{result}->{$name}->{unit}, - value => sprintf("%.2f", $self->{result}->{$name}->{temperature}), - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => 0 - ); - }; - - $self->{output}->display(); - $self->{output}->exit(); -}; - -1; - -__END__ - -=head1 MODE - -Check HDDTEMP Temperature by Socket Connect - -=over 8 - -=item B<--hostname> - -IP Address or FQDN of the Server - -=item B<--port> - -Port used by Hddtemp (Default: 7634) - -=item B<--timeout> - -Set Timeout for Socketconnect - -=item B<--warning> - -Warning Threshold for Temperature - -=item B<--critical> - -Critical Threshold for Temperature - -=item B<--name> - -Set the Harddrive name (empty means 'check all Harddrives') - -=item B<--regexp> - -Allows to use regexp to filter Harddrive (with option --name). - -=item B<--regexp-isensitive> - -Allows to use regexp non case-sensitive (with --regexp). - -=back - -=cut diff --git a/centreon-plugins/centreon/plugins/backend/ssh/libssh.pm b/centreon-plugins/centreon/plugins/backend/ssh/libssh.pm index d38445166..eae3df26c 100644 --- a/centreon-plugins/centreon/plugins/backend/ssh/libssh.pm +++ b/centreon-plugins/centreon/plugins/backend/ssh/libssh.pm @@ -138,7 +138,7 @@ sub execute { $self->{output}->option_exit(); } - if ($exit_code != 0) { + if ($exit_code != 0 && (!defined($options{no_quit}) || $options{no_quit} != 1)) { $self->{output}->add_option_msg(short_msg => sprintf('command execution error [exit code: %s]', $exit_code)); $self->{output}->option_exit(); } diff --git a/centreon-plugins/centreon/plugins/backend/ssh/plink.pm b/centreon-plugins/centreon/plugins/backend/ssh/plink.pm index 1b4f745e2..90aab1a3d 100644 --- a/centreon-plugins/centreon/plugins/backend/ssh/plink.pm +++ b/centreon-plugins/centreon/plugins/backend/ssh/plink.pm @@ -81,7 +81,8 @@ sub execute { ssh_path => $self->{ssh_path}, ssh_option => $self->{ssh_option}, timeout => $options{timeout} - } + }, + no_quit => $options{no_quit} ); if (defined($options{ssh_pipe}) && $options{ssh_pipe} == 1) { diff --git a/centreon-plugins/centreon/plugins/backend/ssh/sshcli.pm b/centreon-plugins/centreon/plugins/backend/ssh/sshcli.pm index 7374b7c21..fd8290212 100644 --- a/centreon-plugins/centreon/plugins/backend/ssh/sshcli.pm +++ b/centreon-plugins/centreon/plugins/backend/ssh/sshcli.pm @@ -83,7 +83,8 @@ sub execute { ssh_path => $self->{ssh_path}, ssh_option => $self->{ssh_option}, timeout => $options{timeout} - } + }, + no_quit => $options{no_quit} ); if (defined($options{ssh_pipe}) && $options{ssh_pipe} == 1) {