From 1ccb6b7c7ce169cf08c28c179afe3a2bfa8e7128 Mon Sep 17 00:00:00 2001 From: qgarnier Date: Tue, 1 Feb 2022 15:36:52 +0100 Subject: [PATCH] (plugin) os::windows::wsman - add modes (#3451) --- centreon-plugins/os/windows/wsman/mode/cpu.pm | 187 ++++++++ .../os/windows/wsman/mode/filesdate.pm | 202 ++++++++ .../os/windows/wsman/mode/filessize.pm | 205 ++++++++ .../os/windows/wsman/mode/interfaces.pm | 445 ++++++++++++++++++ .../os/windows/wsman/mode/listinterfaces.pm | 129 +++++ .../os/windows/wsman/mode/listprocesses.pm | 118 +++++ .../os/windows/wsman/mode/listservices.pm | 2 +- .../os/windows/wsman/mode/liststorages.pm | 122 +++++ .../os/windows/wsman/mode/memory.pm | 126 +++++ .../os/windows/wsman/mode/pages.pm | 137 ++++++ .../os/windows/wsman/mode/processes.pm | 164 +++++++ .../wsman/mode/{service.pm => services.pm} | 36 +- .../os/windows/wsman/mode/storages.pm | 184 ++++++++ .../os/windows/wsman/mode/time.pm | 245 ++++++++++ .../os/windows/wsman/mode/uptime.pm | 161 +++++++ centreon-plugins/os/windows/wsman/plugin.pm | 24 +- 16 files changed, 2467 insertions(+), 20 deletions(-) create mode 100644 centreon-plugins/os/windows/wsman/mode/cpu.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/filesdate.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/filessize.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/interfaces.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/listinterfaces.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/listprocesses.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/liststorages.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/memory.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/pages.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/processes.pm rename centreon-plugins/os/windows/wsman/mode/{service.pm => services.pm} (85%) create mode 100644 centreon-plugins/os/windows/wsman/mode/storages.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/time.pm create mode 100644 centreon-plugins/os/windows/wsman/mode/uptime.pm diff --git a/centreon-plugins/os/windows/wsman/mode/cpu.pm b/centreon-plugins/os/windows/wsman/mode/cpu.pm new file mode 100644 index 000000000..4a2926e85 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/cpu.pm @@ -0,0 +1,187 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); + +sub custom_cpu_avg_calc { + my ($self, %options) = @_; + + my ($skipped, $buffer) = (1, 1); + my ($count, $total_cpu) = (0, 0); + + foreach (keys %{$options{new_datas}}) { + if (/^(.*?cpu\d+)_PercentProcessorTime/) { + my $prefix = $1; + $skipped = 0; + next if (!defined($options{old_datas}->{$_})); + $buffer = 0; + + # + #Cal Method ref: http://technet.microsoft.com/en-us/library/cc757283%28WS.10%29.aspx + # + $total_cpu += (1 - ( $options{new_datas}->{$prefix . '_PercentProcessorTime'} - $options{old_datas}->{$prefix . '_PercentProcessorTime'} ) / + ( $options{new_datas}->{$prefix . '_Timestamp_Sys100NS'} - $options{old_datas}->{$prefix . '_Timestamp_Sys100NS'} ) ) * 100; + $count++; + } + } + + return -10 if ($skipped == 1); + if ($buffer == 1) { + $self->{error_msg} = "Buffer creation"; + return -1; + } + + $self->{result_values}->{prct_used} = $total_cpu / $count; + return 0; +} + +sub custom_cpu_core_calc { + my ($self, %options) = @_; + + # + #Core Calc: (1 - (270377812500 - 247044062500) / + # (132846755243261461 - 132846731625406368) ) * 100 = 1.20292504074261 + # + my $core_usage = (1 - ( $options{new_datas}->{$self->{instance} . '_PercentProcessorTime'} - $options{old_datas}->{$self->{instance} . '_PercentProcessorTime'} ) / + ( $options{new_datas}->{$self->{instance} . '_Timestamp_Sys100NS'} - $options{old_datas}->{$self->{instance} . '_Timestamp_Sys100NS'} ) ) * 100; + $self->{result_values}->{prct_used} = $core_usage; + + return 0; +} + +sub prefix_cpu_core_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'cpu_avg', type => 0 }, + { name => 'cpu_core', type => 1, cb_prefix_output => 'prefix_cpu_core_output' } + ]; + + $self->{maps_counters}->{cpu_avg} = [ + { label => 'average', nlabel => 'cpu.utilization.percentage', set => { + key_values => [], + closure_custom_calc => $self->can('custom_cpu_avg_calc'), + manual_keys => 1, + output_template => 'CPU(s) average usage is %.2f %%', + output_use => 'prct_used', threshold_use => 'prct_used', + perfdatas => [ + { value => 'prct_used', template => '%.2f', + min => 0, max => 100, unit => '%' } + ] + } + } + ]; + + $self->{maps_counters}->{cpu_core} = [ + { label => 'core', nlabel => 'core.cpu.utilization.percentage', set => { + key_values => [ + { name => 'PercentProcessorTime', diff => 1 }, { name => 'Timestamp_Sys100NS', diff => 1 }, { name => 'display' } + ], + closure_custom_calc => $self->can('custom_cpu_core_calc'), + output_template => 'usage: %.2f %%', + output_use => 'prct_used', threshold_use => 'prct_used', + perfdatas => [ + { value => 'prct_used', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1 } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => "select Name,PercentProcessorTime,Timestamp_Sys100NS from Win32_PerfRawData_PerfOS_Processor where Name != '_Total'", + result_type => 'array' + ); + + $self->{cpu_avg} = {}; + $self->{cpu_core} = {}; + foreach (@$results) { + my $cpu_number = $_->{Name}; + + $self->{cpu_core}->{$cpu_number} = { + display => $cpu_number, + PercentProcessorTime => $_->{PercentProcessorTime}, + Timestamp_Sys100NS => $_->{Timestamp_Sys100NS} + }; + $self->{cpu_avg}->{'cpu' . $cpu_number . '_PercentProcessorTime'} = $_->{PercentProcessorTime}; + $self->{cpu_avg}->{'cpu' . $cpu_number . '_Timestamp_Sys100NS'} = $_->{Timestamp_Sys100NS}; + } + + $self->{cache_name} = 'windows_wsman_' . $options{wsman}->get_hostname() . '_' . $options{wsman}->get_port . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); +} + +1; + +__END__ + +=head1 MODE + +Check processor usage. + +=over 8 + +=item B<--warning-average> + +Warning threshold average CPU utilization. + +=item B<--critical-average> + +Critical threshold average CPU utilization. + +=item B<--warning-core> + +Warning thresholds for each CPU core + +=item B<--critical-core> + +Critical thresholds for each CPU core + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/filesdate.pm b/centreon-plugins/os/windows/wsman/mode/filesdate.pm new file mode 100644 index 000000000..6dd5b86d3 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/filesdate.pm @@ -0,0 +1,202 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::filesdate; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use DateTime; +use centreon::plugins::misc; + +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 => { + 'warning:s' => { name => 'warning' }, + 'critical:s' => { name => 'critical' }, + 'filter-filename:s' => { name => 'filter_filename' }, + 'folder:s' => { name => 'folder' } + }); + + 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->{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(); + } + if (!defined($self->{option_results}->{folder}) || $self->{option_results}->{folder} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify folder option."); + $self->{output}->option_exit(); + } + + #### Create file path + $self->{option_results}->{folder} =~ s/\//\\\\/g; +} + +sub wmi_to_seconds { + my ($self, %options) = @_; + + # pass in a WMI Timestamp like 2021-11-04T21:24:11.871719Z + my $sec = ''; + my $age_sec = ''; + my $current_dt = ''; + my $current_sec = ''; + my $tz = ''; + my $timezone_direction = '+'; + my $timezone_offset = 0; + + # 1 2 3 4 5 6 7 8 9 + if ($options{ts} =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d*)(\S+)$/) { + my %ts_info= ( + year => $1, + month => $2, + day => $3, + hour => $4, + minute => $5, + second => $6, + nanosecond => $7, + time_zone => $8 # set later + ); + + + my $dt = DateTime->new(%ts_info); + $sec = $dt->epoch(); + # force the current time into the same timezone as the queried system + $current_dt = DateTime->now(time_zone => $dt->time_zone()); + $current_sec = $current_dt->epoch(); + $age_sec = $current_sec - $sec; + } else { + $self->{output}->add_option_msg(short_msg => 'Wrong time format'); + $self->{output}->option_exit(); + } + + return ($sec, $age_sec); +} + +sub run { + my ($self, %options) = @_; + + my $total_size = 0; + my $current_time = time(); + + $self->{option_results}->{folder} =~ /^(..)(.*)$/; + my ($drive, $path) = ($1, $2); + my $WQL = 'Select name, lastmodified from CIM_DataFile where drive = "' . $drive . '" AND path = "' . $path . '"'; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => $WQL, + result_type => 'array' + ); + + # + #$VAR1 = 'CLASS: CIM_DataFile + #LastModified;Name + #20211224000036.262291+000;C:\\Users\\Administrator\\NTUSER.DAT'; + # + $self->{output}->output_add( + severity => 'OK', + short_msg => 'All files times are ok.' + ); + + if (!defined($results) || scalar(@$results) <= 0) { + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => 'No file found.' + ); + } + + foreach (@$results) { + my $last_modified = $_->{LastModified}; + my $name = centreon::plugins::misc::trim($_->{Name}); + my ($time, $diff_time) = $self->wmi_to_seconds(ts => $last_modified); + + next if (defined($self->{option_results}->{filter_filename}) && $self->{option_results}->{filter_filename} ne '' && + $name !~ /$self->{option_results}->{filter_filename}/); + + my $exit_code = $self->{perfdata}->threshold_check( + value => $diff_time, + threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ] + ); + $self->{output}->output_add(long_msg => sprintf("%s: %s seconds (time: %s)", $name, $diff_time, scalar(localtime($time)))); + if (!$self->{output}->is_status(litteral => 1, value => $exit_code, compare => 'ok')) { + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf('%s: %s seconds (time: %s)', $name, $diff_time, scalar(localtime($time))) + ); + } + $self->{output}->perfdata_add( + label => $name, + nlabel => 'file.mtime.last.seconds', + unit => 's', + instances => $name, + value => $diff_time, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical') + ); + } + + $self->{output}->display(); + $self->{output}->exit(); +} + +1; + +__END__ + +=head1 MODE + +Check files modified time. + +=over 8 + +=item B<--folder> + +Folder to check. (No WQL wildcard allowed) +Ex: 'C:/Users/Administrator/'. + +=item B<--filter-filename> + +Filter files by name. + +=item B<--warning> + +Threshold warning in seconds for each files (diff time). + +=item B<--critical> + +Threshold critical in seconds for each files (diff time). + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/filessize.pm b/centreon-plugins/os/windows/wsman/mode/filessize.pm new file mode 100644 index 000000000..dac35bb63 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/filessize.pm @@ -0,0 +1,205 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::filessize; + +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, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'warning-one:s' => { name => 'warning_one' }, + 'critical-one:s' => { name => 'critical_one' }, + 'warning-total:s' => { name => 'warning_total' }, + 'critical-total:s' => { name => 'critical_total' }, + 'all-files' => { name => 'all_files' }, + 'filter-plugin:s' => { name => 'filter_plugin' }, + 'folder:s' => { name => 'folder' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + if (($self->{perfdata}->threshold_validate(label => 'warning_one', value => $self->{option_results}->{warning_one})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong warning-one threshold '" . $self->{warning_one} . "'."); + $self->{output}->option_exit(); + } + if (($self->{perfdata}->threshold_validate(label => 'critical_one', value => $self->{option_results}->{critical_one})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong critical-one threshold '" . $self->{critical_one} . "'."); + $self->{output}->option_exit(); + } + if (($self->{perfdata}->threshold_validate(label => 'warning_total', value => $self->{option_results}->{warning_total})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong warning-total threshold '" . $self->{warning_total} . "'."); + $self->{output}->option_exit(); + } + if (($self->{perfdata}->threshold_validate(label => 'critical_total', value => $self->{option_results}->{critical_total})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong critical-total threshold '" . $self->{critical_total} . "'."); + $self->{output}->option_exit(); + } + if (!defined($self->{option_results}->{folder}) || $self->{option_results}->{folder} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify folder option."); + $self->{output}->option_exit(); + } + + #### Create file path + $self->{option_results}->{folder} =~ s/\//\\\\/g; +} + +sub run { + my ($self, %options) = @_; + + my ($total_size, $exit_code) = (0); + + $self->{option_results}->{folder} =~ /^(..)(.*)$/; + my ($drive, $path) = ($1, $2); + my $WQL = 'Select name,filesize from CIM_DataFile where drive = "' . $drive . '" AND path = "' . $path . '"'; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => $WQL, + result_type => 'array' + ); + # + #CLASS: CIM_DataFile + #FileSize|Name + #1092|C:\Users\Administrator\.bash_history + #52|C:\Users\Administrator\.gitconfig + #37|C:\Users\Administrator\.lesshst + #1038|C:\Users\Administrator\.viminfo + #20|C:\Users\Administrator\ntuser.ini + # + + $self->{output}->output_add( + severity => 'OK', + short_msg => "All file sizes are ok." + ); + if (!defined($results) || scalar(@$results) <= 0) { + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => 'No file found.' + ); + } + + foreach (@$results) { + my $size = $_->{FileSize}; + my $name = centreon::plugins::misc::trim($_->{Name}); + + next if (defined($self->{option_results}->{filter_filename}) && $self->{option_results}->{filter_filename} ne '' && + $name !~ /$self->{option_results}->{filter_filename}/); + + $total_size += $size; + my $exit_code = $self->{perfdata}->threshold_check( + value => $size, + threshold => [ { label => 'critical_one', exit_litteral => 'critical' }, { label => 'warning_one', exit_litteral => 'warning' } ] + ); + my ($size_value, $size_unit) = $self->{perfdata}->change_bytes(value => $size); + $self->{output}->output_add(long_msg => sprintf("%s: %s", $name, $size_value . ' ' . $size_unit)); + if (!$self->{output}->is_status(litteral => 1, value => $exit_code, compare => 'ok')) { + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf("'%s' size is %s", $name, $size_value . ' ' . $size_unit) + ); + } + $self->{output}->perfdata_add( + nlabel => 'file.size.bytes', + unit => 'B', + instances => $name, + value => $size, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning_one'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical_one'), + min => 0 + ); + } + + # Total Size + $exit_code = $self->{perfdata}->threshold_check( + value => $total_size, + threshold => [ { label => 'critical_total', exit_litteral => 'critical' }, { label => 'warning_total', exit_litteral => 'warning' } ] + ); + my ($size_value, $size_unit) = $self->{perfdata}->change_bytes(value => $total_size); + $self->{output}->output_add(long_msg => sprintf("Total: %s", $size_value . ' ' . $size_unit)); + if (!$self->{output}->is_status(litteral => 1, value => $exit_code, compare => 'ok')) { + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf('Total size is %s', $size_value . ' ' . $size_unit) + ); + } + $self->{output}->perfdata_add( + nlabel => 'files.size.bytes', + unit => 'B', + value => $total_size, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning_total'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical_total'), + min => 0 + ); + + $self->{output}->display(); + $self->{output}->exit(); +} + +1; + +__END__ + +=head1 MODE + +Check size of files/directories. + +=over 8 + +=item B<--folder> + +Folder to check. (No WQL wildcard allowed) +Ex: 'C:/Users/Administrator/'. + +=item B<--filter-filename> + +Filter files by name. + +=item B<--warning-one> + +Threshold warning in bytes for each files/directories. + +=item B<--critical-one> + +Threshold critical in bytes for each files/directories. + +=item B<--warning-total> + +Threshold warning in bytes for all files/directories. + +=item B<--critical-total> + +Threshold critical in bytes for all files/directories. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/interfaces.pm b/centreon-plugins/os/windows/wsman/mode/interfaces.pm new file mode 100644 index 000000000..5716d8439 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/interfaces.pm @@ -0,0 +1,445 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::interfaces; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use Digest::MD5 qw(md5_hex); + +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my ($warning, $critical); + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} =~ /bps|counter/) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}); + } + + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { + my $nlabel = $self->{nlabel}; + $nlabel =~ s/bitspersecond/bits/; + $self->{output}->perfdata_add( + nlabel => $nlabel, + unit => 'b', + instances => $self->{result_values}->{display}, + value => $self->{result_values}->{traffic_counter}, + warning => $warning, + critical => $critical, + min => 0 + ); + } else { + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => sprintf('%.2f', $self->{result_values}->{traffic_per_seconds}), + warning => $warning, + critical => $critical, + min => 0, max => $self->{result_values}->{speed} + ); + } +} + +sub custom_traffic_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_prct}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'bps') { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_per_seconds}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_counter}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } + return $exit; +} + +sub custom_traffic_output { + my ($self, %options) = @_; + + my ($traffic_value, $traffic_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic_per_seconds}, network => 1); + return sprintf( + 'traffic %s: %s/s (%s)', + $self->{result_values}->{label}, $traffic_value . $traffic_unit, + defined($self->{result_values}->{traffic_prct}) ? sprintf('%.2f%%', $self->{result_values}->{traffic_prct}) : '-' + ); +} +sub custom_traffic_calc { + my ($self, %options) = @_; + + $self->{result_values}->{traffic_per_seconds} = ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}}) / + (($options{new_datas}->{$self->{instance} . '_Timestamp_Sys100NS'} - $options{old_datas}->{$self->{instance} . '_Timestamp_Sys100NS'}) / + $options{new_datas}->{$self->{instance} . '_Frequency_Sys100NS'}); + $self->{result_values}->{traffic_counter} = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref} }; + + $self->{result_values}->{traffic_per_seconds} = sprintf('%d', $self->{result_values}->{traffic_per_seconds}); + + if (defined($options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}) && + $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} ne '' && + $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} > 0) { + $self->{result_values}->{traffic_prct} = $self->{result_values}->{traffic_per_seconds} * 100 / $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + $self->{result_values}->{speed} = $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + } + + $self->{result_values}->{label} = $options{extra_options}->{label_ref}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +############## +# Errors +sub custom_errors_perfdata { + my ($self, %options) = @_; + + if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { + my $nlabel = $self->{nlabel}; + $nlabel =~ s/count$/percentage/; + + $self->{output}->perfdata_add( + nlabel => $nlabel, + unit => '%', + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => sprintf('%.2f', $self->{result_values}->{prct}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100 + ); + } else { + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => $self->{result_values}->{used}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{total} + ); + } +} + +sub custom_errors_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{prct}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } else { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{used}, threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } + return $exit; +} + +sub custom_errors_output { + my ($self, %options) = @_; + + return sprintf( + 'packets %s: %.2f%% (%s on %s)', + $self->{result_values}->{label}, + $self->{result_values}->{prct}, + $self->{result_values}->{used}, + $self->{result_values}->{total} + ); +} + +sub custom_errors_calc { + my ($self, %options) = @_; + + my $errors = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }; + my $errors_diff = ($options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} } - $options{old_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }) / + (($options{new_datas}->{$self->{instance} . '_Timestamp_Sys100NS'} - $options{old_datas}->{$self->{instance} . '_Timestamp_Sys100NS'}) / + $options{new_datas}->{$self->{instance} . '_Frequency_Sys100NS'}); + my $total = $options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}; + my $total_diff = ($options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'} - $options{old_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}) / + (($options{new_datas}->{$self->{instance} . '_Timestamp_Sys100NS'} - $options{old_datas}->{$self->{instance} . '_Timestamp_Sys100NS'}) / + $options{new_datas}->{$self->{instance} . '_Frequency_Sys100NS'}); + + $errors_diff = sprintf('%d', $errors_diff); + $total_diff = sprintf('%d', $total_diff); + $self->{result_values}->{prct} = 0; + $self->{result_values}->{used} = $errors_diff; + $self->{result_values}->{total} = $total_diff; + if ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent_delta') { + $self->{result_values}->{prct} = $errors_diff * 100 / $total_diff if ($total_diff > 0); + } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent') { + $self->{result_values}->{prct} = $errors * 100 / $total if ($total > 0); + $self->{result_values}->{used} = $errors; + } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'delta') { + $self->{result_values}->{used} = $errors_diff; + } else { + $self->{result_values}->{used} = $errors; + $self->{result_values}->{total} = $total; + } + + if (defined($options{extra_options}->{label})) { + $self->{result_values}->{label} = $options{extra_options}->{label}; + } else { + $self->{result_values}->{label} = $options{extra_options}->{label_ref1} . ' ' . $options{extra_options}->{label_ref2}; + } + $self->{result_values}->{label1} = $options{extra_options}->{label_ref1}; + $self->{result_values}->{label2} = $options{extra_options}->{label_ref2}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub prefix_interface_output { + my ($self, %options) = @_; + + return "Interface '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'interfaces', type => 1, cb_prefix_output => 'prefix_interface_output', message_multiple => 'All interfaces are ok', skipped_code => { -10 => 1 } }, + ]; + + $self->{maps_counters}->{interfaces} = [ + { label => 'in-traffic', filter => 'add_traffic', nlabel => 'interface.traffic.in.bitspersecond', set => { + key_values => [ { name => 'in', diff => 1 }, { name => 'Timestamp_Sys100NS' }, { name => 'Frequency_Sys100NS' }, { name => 'speed_in' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'in' }, + closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic in: %s', + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold') + } + }, + { label => 'out-traffic', filter => 'add_traffic', nlabel => 'interface.traffic.out.bitspersecond', set => { + key_values => [ { name => 'out', diff => 1 }, { name => 'Timestamp_Sys100NS' }, { name => 'Frequency_Sys100NS' }, { name => 'speed_out' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'out' }, + closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic out: %s', + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold') + } + }, + { label => 'in-discard', filter => 'add_errors', nlabel => 'interface.packets.in.discard.count', set => { + key_values => [ { name => 'indiscard', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' }, { name => 'Frequency_Sys100NS' }, { name => 'Timestamp_Sys100NS' } ], + closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'discard' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'packets in discard: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + }, + { label => 'in-error', filter => 'add_errors', nlabel => 'interface.packets.in.error.count', set => { + key_values => [ { name => 'inerror', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' }, { name => 'Frequency_Sys100NS' }, { name => 'Timestamp_Sys100NS' } ], + closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'error' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'packets in error: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + }, + { label => 'out-discard', filter => 'add_errors', nlabel => 'interface.packets.out.discard.count', set => { + key_values => [ { name => 'outdiscard', diff => 1 }, { name => 'total_out_packets', diff => 1 }, { name => 'display' }, { name => 'Frequency_Sys100NS' }, { name => 'Timestamp_Sys100NS' } ], + closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'out', label_ref2 => 'discard' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'packets out discard: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + }, + { label => 'out-error', filter => 'add_errors', nlabel => 'interface.packets.out.error.count', set => { + key_values => [ { name => 'outerror', diff => 1 }, { name => 'total_out_packets', diff => 1 }, { name => 'display' }, { name => 'Frequency_Sys100NS' }, { name => 'Timestamp_Sys100NS' } ], + closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'out', label_ref2 => 'error' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'packets out error: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'add-traffic' => { name => 'add_traffic' }, + 'add-errors' => { name => 'add_errors' }, + 'filter-interface:s' => { name => 'filter_interface' }, + 'exclude-interface:s' => { name => 'exclude_interface' }, + 'units-traffic:s' => { name => 'units_traffic', default => 'percent_delta' }, + 'units-errors:s' => { name => 'units_errors', default => 'percent_delta' }, + 'speed:s' => { name => 'speed' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + # If no options, we set add-traffic + if (!defined($self->{option_results}->{add_traffic}) && + !defined($self->{option_results}->{add_errors})) { + $self->{option_results}->{add_traffic} = 1; + } + + if (defined($self->{option_results}->{speed}) && $self->{option_results}->{speed} ne '') { + if ($self->{option_results}->{speed} !~ /^[0-9]+(\.[0-9]+){0,1}$/) { + $self->{output}->add_option_msg(short_msg => "Speed must be a positive number '" . $self->{option_results}->{speed} . "' (can be a float also)."); + $self->{output}->option_exit(); + } else { + $self->{option_results}->{speed} *= 1000000; + } + } + + if (defined($self->{option_results}->{add_traffic})) { + $self->{option_results}->{units_traffic} = 'percent_delta' + if (!defined($self->{option_results}->{units_traffic}) || + $self->{option_results}->{units_traffic} eq '' || + $self->{option_results}->{units_traffic} eq '%'); + if ($self->{option_results}->{units_traffic} !~ /^(?:percent|percent_delta|bps|counter)$/) { + $self->{output}->add_option_msg(short_msg => 'Wrong option --units-traffic.'); + $self->{output}->option_exit(); + } + } + + if (defined($self->{option_results}->{add_errors})) { + $self->{option_results}->{units_errors} = 'percent_delta' + if (!defined($self->{option_results}->{units_errors}) || + $self->{option_results}->{units_errors} eq '' || + $self->{option_results}->{units_errors} eq '%'); + if ($self->{option_results}->{units_errors} !~ /^(?:percent|percent_delta|delta|counter)$/) { + $self->{output}->add_option_msg(short_msg => 'Wrong option --units-errors.'); + $self->{output}->option_exit(); + } + } + +} + +sub do_selection { + my ($self, %options) = @_; + + my $WQL = 'Select CurrentBandwidth,BytesReceivedPerSec,BytesSentPerSec,Name,Frequency_Sys100NS,OutputQueueLength,PacketsReceivedErrors,PacketsReceivedPerSec,PacketsSentPerSec,Timestamp_Sys100NS, PacketsOutboundErrors,PacketsReceivedDiscarded, PacketsOutboundDiscarded from Win32_PerfRawData_Tcpip_NetworkInterface'; + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => $WQL, + result_type => 'array' + ); + + # + #'CLASS: Win32_PerfRawData_Tcpip_NetworkInterface + #BytesReceivedPersec;BytesSentPersec;CurrentBandwidth;Frequency_Sys100NS;Name;OutputQueueLength;PacketsOutboundDiscarded;PacketsOutboundErrors;PacketsReceivedDiscarded;PacketsReceivedErrors;PacketsReceivedPersec;PacketsSentPersec;Timestamp_Sys100NS + #7784631;2497355;1000000000;10000000;AWS PV Network Device _0;0;0;0;5;0;11351;7746;132869914560700000 + # + $self->{interfaces} = {}; + foreach (@$results) { + next if (defined($self->{option_results}->{filter_interface}) && $self->{option_results}->{filter_interface} ne '' && + $self->{interface} !~ /$self->{option_results}->{filter_interface}/); + next if (defined($self->{option_results}->{exclude_interface}) && $self->{option_results}->{exclude_interface} ne '' && + $_->{Name} =~ /$self->{option_results}->{exclude_interface}/); + + $self->{interfaces}->{ $_->{Name} } = { + display => $_->{Name}, + speed_in => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $_->{CurrentBandwidth}, + speed_out => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $_->{CurrentBandwidth}, + Frequency_Sys100NS => $_->{Frequency_Sys100NS}, + Timestamp_Sys100NS => $_->{Timestamp_Sys100NS}, + in => $_->{BytesReceivedPersec} * 8, + out => $_->{BytesSentPersec} * 8, + indiscard => $_->{PacketsReceivedDiscarded}, + inerror => $_->{PacketsReceivedErrors}, + outdiscard => $_->{PacketsOutboundDiscarded}, + outerror => $_->{PacketsOutboundErrors}, + total_out_packets => $_->{PacketsSentPersec}, + total_in_packets => $_->{PacketsReceivedPersec} + }; + } + + if (scalar(keys %{$self->{interfaces}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No interface found."); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->do_selection(wsman => $options{wsman}); + $self->{cache_name} = 'windows_wsman_' . $options{wsman}->get_hostname() . '_' . $options{wsman}->get_port() . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_interface}) ? md5_hex($self->{option_results}->{filter_interface}) : md5_hex('all')); +} + +1; + +__END__ + +=head1 MODE + +Check interfaces. + +=over 8 + +=item B<--add-errors> + +Check interface errors. + +=item B<--warning-in> + +Threshold warning in percent for 'in' traffic. + +=item B<--critical-in> + +Threshold critical in percent for 'in' traffic. + +=item B<--warning-out> + +Threshold warning in percent for 'out' traffic. + +=item B<--critical-out> + +Threshold critical in percent for 'out' traffic. + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'in-error', 'in-discard', 'out-error', 'out-discard', + +=item B<--units-traffic> + +Units of thresholds for the traffic (Default: 'percent_delta') ('percent_delta', 'bps', 'counter'). + +=item B<--units-errors> + +Units of thresholds for errors/discards (Default: 'percent_delta') ('percent_delta', 'percent', 'delta', 'counter'). + +=item B<--filter-interface> + +Filter interface name (regexp can be used). + +=item B<--exclude-interface> + +Exclude interface name (regexp can be used). + +=item B<--speed> + +Set interface speed (in Mb). + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/listinterfaces.pm b/centreon-plugins/os/windows/wsman/mode/listinterfaces.pm new file mode 100644 index 000000000..d9533606d --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/listinterfaces.pm @@ -0,0 +1,129 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::listinterfaces; + +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); +} + +my @labels = ('name', 'status', 'speed', 'enabled'); +my $map_status = { + 0 => 'down', + 1 => 'connecting', + 2 => 'up', + 3 => 'disconnecting', + 4 => 'hardwareNotPresent', + 5 => 'hardwareDisable', + 6 => 'hardwarMalfunction', + 7 => 'mediaDisconnect', + 8 => 'auth', + 9 => 'authSucceeded', + 10 => 'ÁuthFailed', + 11 => 'invalidAddress', + 12 => 'credentialsRequired' +}; + +sub manage_selection { + my ($self, %options) = @_; + + my $entries = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => 'Select DeviceID, Name, MaxSpeed, NetConnectionStatus, NetEnabled from Win32_NetworkAdapter', + result_type => 'array' + ); + + my $results = {}; + foreach (@$entries) { + my $status = (!defined($_->{NetConnectionStatus}) || $_->{NetConnectionStatus} eq '') ? 0 : $_->{NetConnectionStatus}; + $results->{ $_->{DeviceID} } = { + name => $_->{Name}, + speed => (!defined($_->{MaxSpeed}) || $_->{MaxSpeed} eq '') ? 0 : $_->{MaxSpeed}, + status => $map_status->{$status}, + enabled => (!defined($_->{NetEnabled}) || $_->{NetEnabled} eq '') ? 'false' : $_->{NetEnabled} + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List interfaces:' + ); + $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 => [@labels]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} +1; + +__END__ + +=head1 MODE + +List interfaces. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/listprocesses.pm b/centreon-plugins/os/windows/wsman/mode/listprocesses.pm new file mode 100644 index 000000000..1e2f61db8 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/listprocesses.pm @@ -0,0 +1,118 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::listprocesses; + +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); +} + +my @labels = ('name', 'pid', 'status'); +my %map_process_status = ( + 0 => 'running', + 1 => 'other', + 2 => 'ready', + 3 => 'running', + 4 => 'blocked' +); + +sub manage_selection { + my ($self, %options) = @_; + + my $entries = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => 'select Name,ExecutionState,CommandLine,ExecutablePath,Handle from Win32_Process', + result_type => 'array' + ); + + my $results = []; + foreach (@$entries) { + my $status = (!defined($_->{ExecutionState}) || $_->{ExecutionState} eq '') ? 0 : $_->{ExecutionState}; + push @$results, { + name => $_->{Name}, + status => $map_process_status{$status}, + pid => $_->{Handle} + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach my $entry (@$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $entry->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List processes:' + ); + $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 => [@labels]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach my $entry (@$results) { + $self->{output}->add_disco_entry(%$entry); + } +} +1; + +__END__ + +=head1 MODE + +List processes. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/listservices.pm b/centreon-plugins/os/windows/wsman/mode/listservices.pm index 9558784b3..cba4d4549 100644 --- a/centreon-plugins/os/windows/wsman/mode/listservices.pm +++ b/centreon-plugins/os/windows/wsman/mode/listservices.pm @@ -1,5 +1,5 @@ # -# Copyright 2022 Centreon (http://www.centreon.com/) +# Copyright 2021 Centreon (http://www.centreon.com/) # # Centreon is a full-fledged industry-strength solution that meets # the needs in IT infrastructure and application monitoring for diff --git a/centreon-plugins/os/windows/wsman/mode/liststorages.pm b/centreon-plugins/os/windows/wsman/mode/liststorages.pm new file mode 100644 index 000000000..d07856e7f --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/liststorages.pm @@ -0,0 +1,122 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::liststorages; + +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); +} + +my @labels = ('size', 'name', 'label', 'type'); +my $map_types = { + 0 => 'unknown', + 1 => 'noRootDirectory', + 2 => 'removableDisk', + 3 => 'localDisk', + 4 => 'networkDrive', + 5 => 'compactDisc', + 6 => 'ramDisk' +}; + +sub manage_selection { + my ($self, %options) = @_; + + my $entries = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => 'Select Capacity,DeviceID,DriveLetter,DriveType,FileSystem,FreeSpace,Label,Name from Win32_Volume', + result_type => 'array' + ); + + my $results = {}; + foreach my $entry (@$entries) { + $results->{ $entry->{DeviceID} } = { + size => $entry->{Capacity}, + name => $entry->{Name}, + label => $entry->{Label}, + type => $map_types->{ $entry->{DriveType} } + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List storages:' + ); + $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 => [@labels]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(wsman => $options{wsman}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} +1; + +__END__ + +=head1 MODE + +List storages. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/memory.pm b/centreon-plugins/os/windows/wsman/mode/memory.pm new file mode 100644 index 000000000..4c8fbea16 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/memory.pm @@ -0,0 +1,126 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + return sprintf( + 'Memory usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'memory', type => 0 } + ]; + + $self->{maps_counters}->{memory} = [ + { label => 'usage', nlabel => 'memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'usage-free', nlabel => 'memory.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'usage-prct', nlabel => 'memory.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'free' }, { name => 'used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; +} + +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 => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => "Select Name,FreePhysicalMemory,TotalVisibleMemorySize from Win32_OperatingSystem", + result_type => 'array' + ); + + foreach (@$results) { + my $free = $_->{FreePhysicalMemory} * 1024; + my $total = $_->{TotalVisibleMemorySize} * 1024; + $self->{memory} = { + total => $total, + used => $total - $free, + free => $free, + prct_free => $free * 100 / $total, + prct_used => 100 - ($free * 100 / $total) + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check memory. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'usage' (B), 'usage-free' (B), 'usage-prct'. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/pages.pm b/centreon-plugins/os/windows/wsman/mode/pages.pm new file mode 100644 index 000000000..7a6278488 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/pages.pm @@ -0,0 +1,137 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::pages; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + return sprintf( + 'space usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} + ); +} + +sub prefix_file_output { + my ($self, %options) = @_; + + return "Page file '" . $options{instance} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'files', type => 1, cb_prefix_output => 'prefix_file_output', message_multiple => 'All page files are ok' } + ]; + + $self->{maps_counters}->{files} = [ + { label => 'space-usage', nlabel => 'page.space.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'space-usage-free', nlabel => 'page.space.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'space-usage-prct', nlabel => 'page.space.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'free' }, { name => 'used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 } + ] + } + } + ]; +} + +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 => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => "Select Name,AllocatedBaseSize,CurrentUsage,PeakUsage from Win32_PageFileUsage", + result_type => 'array' + ); + + $self->{files} = {}; + foreach (@$results) { + my ($total, $used) = ($_->{AllocatedBaseSize} * 1024 * 1024, $_->{CurrentUsage} * 1024 * 1024); + $self->{files}->{ $_->{Name} } = { + total => $total, + used => $used, + free => $total - $used, + prct_free => 100 - ($used * 100 / $total), + prct_used => $used * 100 / $total + }; + } + + if (scalar(keys %{$self->{files}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'Cannot find page files'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check page files. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'space-usage' (B), 'space-usage-free' (B), 'space-usage-prct'. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/processes.pm b/centreon-plugins/os/windows/wsman/mode/processes.pm new file mode 100644 index 000000000..3e71cc0ef --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/processes.pm @@ -0,0 +1,164 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::processes; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +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 => { + 'process-status:s' => { name => 'process_status', default => 'running' }, + 'process-name:s' => { name => 'process_name' }, + 'regexp-name' => { name => 'regexp_name' }, + 'warning:s' => { name => 'warning' }, + 'critical:s' => { name => 'critical' } + }); + + 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->{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(); + } +} + +my %map_process_status = ( + 0 => 'running', + 1 => 'other', + 2 => 'ready', + 3 => 'running', + 4 => 'blocked' +); + +sub run { + my ($self, %options) = @_; + + my $WQL = 'select Name,ExecutionState,CommandLine,ExecutablePath,Handle from Win32_Process'; + if (defined($self->{option_results}->{process_name}) && $self->{option_results}->{process_name} ne '') { + if (defined($self->{option_results}->{regexp_name})) { + $WQL .= ' where Name like "' . $self->{option_results}->{process_name} . '"'; + } else { + $WQL .= ' where Name = "' . $self->{option_results}->{process_name} . '"'; + } + } + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => $WQL, + result_type => 'array' + ); + + # + #CLASS: Win32_Process + #CommandLine;ExecutablePath;ExecutionState;Handle;Name + #C:\\Windows\\system32\\svchost.exe -k DcomLaunch -p;C:\\Windows\\system32\\svchost.exe;0;864;svchost.exe + #"fontdrvhost.exe";C:\\Windows\\system32\\fontdrvhost.exe;0;884;fontdrvhost.exe + #"fontdrvhost.exe";C:\\Windows\\system32\\fontdrvhost.exe;0;892;fontdrvhost.exe + #C:\\Windows\\system32\\svchost.exe -k RPCSS -p;C:\\Windows\\system32\\svchost.exe;0;964;svchost.exe + # + my $detected = 0; + foreach (@$results) { + my $status = (!defined($_->{ExecutionState}) || $_->{ExecutionState} eq '') ? 0 : $_->{ExecutionState}; + $self->{output}->output_add(long_msg => + sprintf( + "Process %s [status: %s] [name: %s]", + $_->{Handle}, + $map_process_status{$status}, + $_->{Name} + ) + ); + $detected++; + } + + my $exit = $self->{perfdata}->threshold_check( + value => $detected, + threshold => [ + { label => 'critical', exit_litteral => 'critical' }, + { label => 'warning', exit_litteral => 'warning' } + ] + ); + + $self->{output}->output_add( + severity => $exit, + short_msg => "Number of current processes: $detected" + ); + $self->{output}->perfdata_add( + nlabel => 'processes.detected.count', + value => $detected, + 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 system number of processes. + +=over 8 + +=item B<--process-status> + +Filter process status. Can be a regexp. +(Default: 'running'). + +=item B<--process-name> + +Filter process name. + +=item B<--regexp-name> + +Allows to use WQL wildcard to filter process +name (with option --process-name). + +=item B<--warning> + +Threshold warning of matching processes detected. + +=item B<--critical> + +Threshold critical of matching processes detected. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/service.pm b/centreon-plugins/os/windows/wsman/mode/services.pm similarity index 85% rename from centreon-plugins/os/windows/wsman/mode/service.pm rename to centreon-plugins/os/windows/wsman/mode/services.pm index b044a4dfc..a8f6cf69b 100644 --- a/centreon-plugins/os/windows/wsman/mode/service.pm +++ b/centreon-plugins/os/windows/wsman/mode/services.pm @@ -1,5 +1,5 @@ # -# Copyright 2022 Centreon (http://www.centreon.com/) +# Copyright 2021 Centreon (http://www.centreon.com/) # # Centreon is a full-fledged industry-strength solution that meets # the needs in IT infrastructure and application monitoring for @@ -18,7 +18,7 @@ # limitations under the License. # -package os::windows::wsman::mode::service; +package os::windows::wsman::mode::services; use base qw(centreon::plugins::mode); @@ -35,7 +35,7 @@ sub new { 'critical' => { name => 'critical' }, 'services:s' => { name => 'services' }, 'auto' => { name => 'auto' }, - 'exclude:s' => { name => 'exclude' }, + 'exclude:s' => { name => 'exclude' } }); $self->{service_rules} = {}; @@ -111,8 +111,10 @@ sub check_auto { $self->{output}->output_add(long_msg => "Service '" . $self->{result}->{$name}->{Name} . "' state: " . $self->{result}->{$name}->{State}); if ($self->{result}->{$name}->{State} !~ /^running$/i) { - $self->{output}->output_add(severity => $self->{threshold}, - short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State}); + $self->{output}->output_add( + severity => $self->{threshold}, + short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State} + ); } } } @@ -128,20 +130,26 @@ sub check { ); foreach my $name (sort(keys %{$self->{service_rules}})) { if (!defined($self->{result}->{$name})) { - $self->{output}->output_add(severity => 'UNKNOWN', - short_msg => "Service '" . $name . "' not found"); + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => "Service '" . $name . "' not found" + ); next; } $self->{output}->output_add(long_msg => "Service '" . $name . "' state: " . $self->{result}->{$name}->{State}); if ($self->{service_rules}->{$name}->{operator} eq '=' && lc($self->{result}->{$name}->{State}) eq $self->{service_rules}->{$name}->{state}) { - $self->{output}->output_add(severity => $self->{threshold}, - short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State}); + $self->{output}->output_add( + severity => $self->{threshold}, + short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State} + ); } elsif ($self->{service_rules}->{$name}->{operator} eq '!=' && lc($self->{result}->{$name}->{State}) ne $self->{service_rules}->{$name}->{state}) { - $self->{output}->output_add(severity => $self->{threshold}, - short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State}); + $self->{output}->output_add( + severity => $self->{threshold}, + short_msg => "Service '" . $self->{result}->{$name}->{Name} . "' is " . $self->{result}->{$name}->{State} + ); } } } @@ -150,8 +158,10 @@ sub run { my ($self, %options) = @_; $self->{wsman} = $options{wsman}; - $self->{output}->output_add(severity => 'OK', - short_msg => 'All service states are ok'); + $self->{output}->output_add( + severity => 'OK', + short_msg => 'All service states are ok' + ); if (defined($self->{option_results}->{auto})) { $self->check_auto(); } else { diff --git a/centreon-plugins/os/windows/wsman/mode/storages.pm b/centreon-plugins/os/windows/wsman/mode/storages.pm new file mode 100644 index 000000000..39adae453 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/storages.pm @@ -0,0 +1,184 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::storages; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + return sprintf( + 'space usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} + ); +} + +sub prefix_storage_output { + my ($self, %options) = @_; + + return sprintf( + "Storage '%s' [type: %s] ", + $options{instance_value}->{name}, + $options{instance_value}->{type} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 }, + { name => 'storages', type => 1, cb_prefix_output => 'prefix_storage_output', message_multiple => 'All storages are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'detected', nlabel => 'storages.detected.count', display_ok => 0, set => { + key_values => [ { name => 'detected' } ], + output_template => 'Storages detected: %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{storages} = [ + { label => 'space-usage', nlabel => 'storage.space.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'space-usage-free', nlabel => 'storage.space.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'space-usage-prct', nlabel => 'storage.space.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'free' }, { name => 'used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 } + ] + } + } + ]; +} + +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' }, + 'filter-type:s' => { name => 'filter_type', default => 'localDisk' } + }); + + return $self; +} + +my $map_types = { + 0 => 'unknown', + 1 => 'noRootDirectory', + 2 => 'removableDisk', + 3 => 'localDisk', + 4 => 'networkDrive', + 5 => 'compactDisc', + 6 => 'ramDisk' +}; + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => 'Select Capacity,DeviceID,DriveLetter,DriveType,FileSystem,FreeSpace,Label,Name from Win32_Volume', + result_type => 'array' + ); + +# 'CLASS: Win32_Volume', +# 'Capacity;DeviceID;DriveLetter;DriveType;FileSystem;FreeSpace;Label;Name', +# '32210153472;\\\\?\\Volume{1952b268-0000-0000-0000-100000000000}\\;C:;3;NTFS;14982889472;(null);C:\\' + + $self->{global} = { detected => 0 }; + $self->{storages} = {}; + foreach (@$results) { + my $type = $map_types->{ $_->{DriveType} }; + + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $_->{Name} !~ /$self->{option_results}->{filter_name}/); + next if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && + $type !~ /$self->{option_results}->{filter_type}/); + + my ($total, $free) = ($_->{Capacity}, $_->{FreeSpace}); + $self->{storages}->{ $_->{Name} } = { + name => $_->{Name}, + type => $type, + total => $total, + used => $total - $free, + free => $free, + prct_free => $free * 100 / $total, + prct_used => 100 - ($free * 100 / $total) + }; + $self->{global}->{detected}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check storages. + +=over 8 + +=item B<--filter-name> + +Filter storages by name (can be a regexp). + +=item B<--filter-type> + +Filter storages by type (can be a regexp) (Default: 'localDisk'). + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'space-usage' (B), 'space-usage-free' (B), 'space-usage-prct'. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/time.pm b/centreon-plugins/os/windows/wsman/mode/time.pm new file mode 100644 index 000000000..546f09083 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/time.pm @@ -0,0 +1,245 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::time; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use DateTime; + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + 'Time offset %d second(s): %s', + $self->{result_values}->{offset}, + $self->{result_values}->{date} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'offset', type => 0 } + ]; + + $self->{maps_counters}->{offset} = [ + { label => 'offset', nlabel => 'time.offset.seconds', set => { + key_values => [ { name => 'offset' }, { name => 'date' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', unit => 's' } + ] + } + } + ]; +} + +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 => { + 'ntp-hostname:s' => { name => 'ntp_hostname' }, + 'ntp-port:s' => { name => 'ntp_port', default => 123 }, + 'timezone:s' => { name => 'timezone' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (defined($self->{option_results}->{ntp_hostname})) { + centreon::plugins::misc::mymodule_load( + output => $self->{output}, module => 'Net::NTP', + error_msg => "Cannot load module 'Net::NTP'." + ); + } +} + +sub get_from_epoch { + my ($self, %options) = @_; + + my $timezone = 'UTC'; + if (defined($self->{option_results}->{timezone}) && $self->{option_results}->{timezone} ne '') { + $timezone = $self->{option_results}->{timezone}; + } + + my $tz = centreon::plugins::misc::set_timezone(name => $timezone); + my $dt = DateTime->from_epoch( + epoch => $options{date}, + %$tz + ); + my @remote_date = ($dt->year, $dt->month, $dt->day, $dt->hour, $dt->minute, $dt->second); + return ($dt->epoch, \@remote_date, $timezone); +} + +sub get_from_datetime { + my ($self, %options) = @_; + + my @remote_date = ( + $options{year}, + $options{mounth}, + $options{day}, + $options{hour}, + $options{minute}, + $options{second}, + $options{ms} + ); + + my $timezone = 'UTC'; + if (defined($self->{option_results}->{timezone}) && $self->{option_results}->{timezone} ne '') { + $timezone = $self->{option_results}->{timezone}; + } elsif (defined($remote_date[9])) { + $timezone = sprintf('%s%02d%02d', $remote_date[7], $remote_date[8], $remote_date[9]); # format +0630 + } + + my $tz = centreon::plugins::misc::set_timezone(name => $timezone); + my $dt = DateTime->new( + year => $remote_date[0], + month => $remote_date[1], + day => $remote_date[2], + hour => $remote_date[3], + minute => $remote_date[4], + second => $remote_date[5], + %$tz + ); + + return ($dt->epoch, \@remote_date, $timezone); +} + +sub get_target_time { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => "Select * from Win32_UTCTime", + result_type => 'array' + ); + + # + #CLASS: Win32_UTCTime + #Day;DayOfWeek;Hour;Milliseconds;Minute;Month;Quarter;Second;WeekInMonth;Year + #23;4;18;0;56;12;4;45;4;2021 + # + + my ($day, $hour, $minute, $month, $second, $year); + foreach (@$results) { + $day = $_->{Day}; + $hour = $_->{Hour}; + $minute = $_->{Minute}; + $month = $_->{Month}; + $second = $_->{Second}; + $year = $_->{Year}; + } + + return $self->get_from_datetime( + year => $year, + mounth => $month, + day => $day, + hour => $hour, + minute => $minute, + second => $second + ); +} + +sub manage_selection { + my ($self, %options) = @_; + + my ($distant_time, $remote_date, $timezone) = $self->get_target_time(%options); + if ($distant_time == 0) { + $self->{output}->add_option_msg(short_msg => "Couldn't get system date: local time: 0"); + $self->{output}->option_exit(); + } + + my $ref_time; + if (defined($self->{option_results}->{ntp_hostname}) && $self->{option_results}->{ntp_hostname} ne '') { + my %ntp; + + eval { + %ntp = Net::NTP::get_ntp_response($self->{option_results}->{ntp_hostname}, $self->{option_results}->{ntp_port}); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Couldn't connect to ntp server: " . $@); + $self->{output}->option_exit(); + } + + $ref_time = $ntp{'Transmit Timestamp'}; + } else { + $ref_time = time(); + } + + my $offset = $distant_time - $ref_time; + my $remote_date_formated = sprintf( + 'Local Time: %02d-%02d-%02dT%02d:%02d:%02d (%s)', + $remote_date->[0], $remote_date->[1], $remote_date->[2], + $remote_date->[3], $remote_date->[4], $remote_date->[5], $timezone + ); + + $self->{offset} = { + offset => sprintf('%d', $offset), + date => $remote_date_formated + }; +} + +1; + +__END__ + +=head1 MODE + +Check time offset of server with ntp server. Use local time if ntp-host option is not set. +SNMP gives a date with second precision (no milliseconds). Time precision is not very accurate. +Use threshold with (+-) 2 seconds offset (minimum). + +=over 8 + +=item B<--warning-offset> + +Time offset warning threshold (in seconds). + +=item B<--critical-offset> + +Time offset critical Threshold (in seconds). + +=item B<--ntp-hostname> + +Set the ntp hostname (if not set, localtime is used). + +=item B<--ntp-port> + +Set the ntp port (Default: 123). + +=item B<--timezone> + +Set the timezone of distant server. For Windows, you need to set it. +Can use format: 'Europe/London' or '+0100'. + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/mode/uptime.pm b/centreon-plugins/os/windows/wsman/mode/uptime.pm new file mode 100644 index 000000000..a7a52ee84 --- /dev/null +++ b/centreon-plugins/os/windows/wsman/mode/uptime.pm @@ -0,0 +1,161 @@ +# +# Copyright 2022 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 os::windows::wsman::mode::uptime; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use POSIX; +use centreon::plugins::misc; +use Time::HiRes qw(time); + +my $unitdiv = { s => 1, w => 604800, d => 86400, h => 3600, m => 60 }; +my $unitdiv_long = { s => 'seconds', w => 'weeks', d => 'days', h => 'hours', m => 'minutes' }; + +sub custom_uptime_output { + my ($self, %options) = @_; + + return sprintf( + 'System uptime is: %s', + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{uptime}, start => 'd') + ); +} + +sub custom_uptime_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => 'system.uptime.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} }, + unit => $self->{instance_mode}->{option_results}->{unit}, + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); +} + +sub custom_uptime_threshold { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' }, + { label => 'unknown-'. $self->{thlabel}, exit_litteral => 'unknown' } + ] + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'uptime', set => { + key_values => [ { name => 'uptime' } ], + closure_custom_output => $self->can('custom_uptime_output'), + closure_custom_perfdata => $self->can('custom_uptime_perfdata'), + closure_custom_threshold_check => $self->can('custom_uptime_threshold') + } + } + ]; +} + +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 => { + 'unit:s' => { name => 'unit', default => 's' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if ($self->{option_results}->{unit} eq '' || !defined($unitdiv->{$self->{option_results}->{unit}})) { + $self->{option_results}->{unit} = 's'; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{wsman}->request( + uri => 'http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*', + wql_filter => "Select Frequency_Sys100NS,SystemUpTime,Timestamp_Object from Win32_PerfRawData_PerfOS_System", + result_type => 'array' + ); + + # + #CLASS: Win32_PerfRawData_PerfOS_System + #Frequency_Sys100NS;SystemUpTime;Timestamp_Object + #10000000;132847344565000000;132847576466519223 + # + my $uptime = 0; + foreach my $result (@$results) { + my $Frequency_Sys100NS = $result->{Frequency_Sys100NS}; + my $SystemUpTime = $result->{SystemUpTime}; + my $Timestamp_Object = $result->{Timestamp_Object}; + if (!defined($result->{SystemUpTime}) || !defined($result->{Timestamp_Object}) || !defined($result->{Frequency_Sys100NS})) { + $self->{output}->add_option_msg(short_msg => 'Some informations missing.'); + $self->{output}->option_exit(); + } + + $self->{global} = { uptime => ($result->{Timestamp_Object} - $result->{SystemUpTime}) / $result->{Frequency_Sys100NS} }; + } +} + +1; + +__END__ + +=head1 MODE + +Check system uptime. + +=over 8 + +=item B<--warning-uptime> + +Threshold warning. + +=item B<--critical-uptime> + +Threshold critical. + +=item B<--unit> + +Select the unit for performance data and thresholds. May be 's' for seconds, 'm' for minutes, +'h' for hours, 'd' for days, 'w' for weeks. Default is seconds + +=back + +=cut diff --git a/centreon-plugins/os/windows/wsman/plugin.pm b/centreon-plugins/os/windows/wsman/plugin.pm index cc6c89f18..cd87b94b4 100644 --- a/centreon-plugins/os/windows/wsman/plugin.pm +++ b/centreon-plugins/os/windows/wsman/plugin.pm @@ -1,5 +1,5 @@ # -# Copyright 2022 Centreon (http://www.centreon.com/) +# Copyright 2021 Centreon (http://www.centreon.com/) # # Centreon is a full-fledged industry-strength solution that meets # the needs in IT infrastructure and application monitoring for @@ -29,11 +29,23 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $self->{version} = '0.1'; - %{$self->{modes}} = ( - 'list-services' => 'os::windows::wsman::mode::listservices', - 'service' => 'os::windows::wsman::mode::service', - ); + $self->{modes} = { + 'cpu' => 'os::windows::wsman::mode::cpu', + 'files-date' => 'os::windows::wsman::mode::filesdate', + 'files-size' => 'os::windows::wsman::mode::filessize', + 'interfaces' => 'os::windows::wsman::mode::interfaces', + 'list-interfaces' => 'os::windows::wsman::mode::listinterfaces', + 'list-processes' => 'os::windows::wsman::mode::listprocesses', + 'list-services' => 'os::windows::wsman::mode::listservices', + 'list-storages' => 'os::windows::wsman::mode::liststorages', + 'memory' => 'os::windows::wsman::mode::memory', + 'pages' => 'os::windows::wsman::mode::pages', + 'processes' => 'os::windows::wsman::mode::processes', + 'services' => 'os::windows::wsman::mode::services', + 'storages' => 'os::windows::wsman::mode::storages', + 'time' => 'os::windows::wsman::mode::time', + 'uptime' => 'os::windows::wsman::mode::uptime' + }; return $self; }