diff --git a/centreon-plugins/cloud/azure/custom/api.pm b/centreon-plugins/cloud/azure/custom/api.pm index ef8c979df..f075862d6 100644 --- a/centreon-plugins/cloud/azure/custom/api.pm +++ b/centreon-plugins/cloud/azure/custom/api.pm @@ -265,6 +265,22 @@ sub convert_duration { return $duration; } +sub json_decode { + my ($self, %options) = @_; + + $options{content} =~ s/\r//mg; + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($options{content}); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + return $decoded; +} + sub azure_get_metrics_set_url { my ($self, %options) = @_; @@ -655,6 +671,37 @@ sub azure_get_log_analytics { return $response; } +sub azure_get_insights_analytics { + my ($self, %options) = @_; + + my $raw_results = {}; + my $analytics_results = $self->azure_get_log_analytics( + workspace_id => $options{workspace_id}, + query => $options{query}, + timespan => $options{timespan} + ); + + foreach (@{$analytics_results->{tables}}) { + my ($i, $j) = (0, 0); + foreach my $entry (@{$_->{columns}}) { + $raw_results->{index}->{$entry->{name}} = $i; + $i++; + } + + foreach (@{$_->{rows}}) { + $raw_results->{data}->{$j}->{tags} = @$_[$raw_results->{index}->{Tags}]; + $raw_results->{data}->{$j}->{computer} = @$_[$raw_results->{index}->{Computer}]; + if (!defined($options{disco})) { + $raw_results->{data}->{$j}->{timegenerated} = @$_[$raw_results->{index}->{TimeGenerated}]; + $raw_results->{data}->{$j}->{name} = @$_[$raw_results->{index}->{Name}]; + $raw_results->{data}->{$j}->{value} = @$_[$raw_results->{index}->{Val}]; + } + $j++; + } + } + return $raw_results; +} + sub azure_get_publicip_set_url { my ($self, %options) = @_; diff --git a/centreon-plugins/cloud/azure/management/insightsmetrics/mode/cpu.pm b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/cpu.pm new file mode 100644 index 000000000..16ba5a59a --- /dev/null +++ b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/cpu.pm @@ -0,0 +1,187 @@ +# +# 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 +# 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 cloud::azure::management::insightsmetrics::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub computer_long_output { + my ($self, %options) = @_; + + return "Computer '" . $options{instance_value}->{display} . "'"; +} + +sub prefix_core_output { + my ($self, %options) = @_; + + return "CPU #" . $options{instance_value}->{display} . " " ; +} + +sub prefix_avg_output { + my ($self, %options) = @_; + + return $options{instance_value}->{count} . " CPU(s) average utilization: " ; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'computer', type => 3, cb_long_output => 'computer_long_output', indent_long_output => ' ', message_multiple => 'All computers CPUs are OK', + group => [ + { name => 'cpu_avg', display_long => 1, cb_prefix_output => 'prefix_avg_output', type => 0, skipped_code => { -10 => 1 } }, + { name => 'cpu_core', display_long => 1, cb_prefix_output => 'prefix_core_output', message_multiple => 'All CPUs are ok', type => 1, skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{cpu_avg} = [ + { label => 'average-utilization-percentage', nlabel => 'azure.insights.cpu.average.utilization.percentage', set => { + key_values => [ { name => 'average' }, { name => 'count' } ], + output_template => '%.2f %%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' }, + ], + } + }, + ]; + + $self->{maps_counters}->{cpu_core} = [ + { label => 'core-utilization-percentage', nlabel => 'azure.insights.cpu.core.utilization.percentage', set => { + key_values => [ { name => 'utilizationpercentage' }, { name => 'display' } ], + output_template => 'usage : %.2f %%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + ]; +} + +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-computer:s' => { name => 'filter_computer' }, + 'filter-cpu:s' => { name => 'filter_cpu' }, + 'workspace-id:s' => { name => 'workspace_id' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + + +sub manage_selection { + my ($self, %options) = @_; + + my $query = 'InsightsMetrics | where Namespace == "Processor" | summarize arg_max(TimeGenerated, *) by Tags, Name, Computer'; + $query .= '| where Computer == "' . $self->{option_results}->{filter_computer} . '"' if defined $self->{option_results}->{filter_computer} && $self->{option_results}->{filter_computer} ne ''; + + my $results = $options{custom}->azure_get_insights_analytics( + workspace_id => $self->{option_results}->{workspace_id}, + query => $query, + timespan => $self->{option_results}->{timespan} + ); + + my $decoded_tag; + foreach my $entry (keys %{$results->{data}}) { + $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + next if (defined($self->{option_results}->{filter_cpu}) && $decoded_tag->{"vm.azm.ms\/totalCpus"} !~ m/$self->{option_results}->{filter_cpu}/); + + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{display} = $results->{data}->{$entry}->{computer}; + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{cpu_core}->{$decoded_tag->{"vm.azm.ms/totalCpus"}}->{display} = $decoded_tag->{"vm.azm.ms/totalCpus"}; + + } + + foreach my $computer (keys %{$self->{computer}}) { + my $cpu_avg; + foreach my $cpu (keys %{$self->{computer}->{$computer}->{cpu_core}}) { + foreach my $entry (keys %{$results->{data}}) { + $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + my $cpu_id = $decoded_tag->{"vm.azm.ms/totalCpus"}; + next if ($cpu_id !~ m/$cpu/); + + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{cpu_core}->{$cpu_id}->{utilizationpercentage} = $results->{data}->{$entry}->{value}; + $cpu_avg += $results->{data}->{$entry}->{value}; + } + + if (scalar(keys %{$self->{computer}->{$computer}->{cpu_core}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No CPU found for computer " . $self->{computer}->{$computer}->{display}); + $self->{output}->option_exit(); + } + } + if (!defined($self->{option_results}->{filter_cpu}) || $self->{option_results}->{filter_cpu} eq '') { + $self->{computer}->{$computer}->{cpu_avg}->{count} = scalar(keys %{$self->{computer}->{$computer}}); + $self->{computer}->{$computer}->{cpu_avg}->{average} = $cpu_avg / $self->{computer}->{$computer}->{cpu_avg}->{count}; + } + } + + if (scalar(keys %{$self->{computer}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No computer found. Can be: filters, cache file."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check Aure VM CPUs using Insights metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::azure::management::insightsmetrics::plugin --custommode=api --mode=cpu +--subscription=1111 --tenant=2222 --client-id=3333 --client-secret=4444 --workspace-id=5555 --verbose + +=over 8 + +=item B<--filter-computer> + +Filter on a specific Azure "computer". + +=item B<--filter-cpu> + +Filter on specific CPU ID. + +=item B<--warning-*> + +Warning threshold where '*' can be: +'average-utilization-percentage', 'core-utilization-percentage' + +=item B<--critical-*> + +Critical threshold where '*' can be: +'average-utilization-percentage', 'core-utilization-percentage' + +=back + +=cut diff --git a/centreon-plugins/cloud/azure/management/insightsmetrics/mode/listlogicaldisks.pm b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/listlogicaldisks.pm new file mode 100644 index 000000000..5d8c9fdb6 --- /dev/null +++ b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/listlogicaldisks.pm @@ -0,0 +1,114 @@ +# +# 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 +# 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 cloud::azure::management::insightsmetrics::mode::listlogicaldisks; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use JSON::XS; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'computer:s' => { name => 'computer' }, + 'workspace-id:s' => { name => 'workspace_id' } + }); + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + if (!defined($self->{option_results}->{computer}) || $self->{option_results}->{computer} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --computer option."); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $query = 'InsightsMetrics | where Namespace == "LogicalDisk" | distinct Tags, Computer | where Computer == "' . $self->{option_results}->{computer} . '"'; + + my $results = $options{custom}->azure_get_insights_analytics( + workspace_id => $self->{option_results}->{workspace_id}, + query => $query, + timespan => $self->{option_results}->{timespan}, + disco => 1 + ); + + + foreach my $entry (keys %{$results->{data}}) { + my $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + + $self->{logicaldisk}->{$decoded_tag->{"vm.azm.ms/mountId"}}->{name} = $decoded_tag->{"vm.azm.ms/mountId"}; + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $mount (sort keys %{$self->{logicaldisk}}) { + $self->{output}->output_add(long_msg => '[name = ' . $mount . ']' ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List logical disks:' + ); + $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) = @_; + + $self->manage_selection(%options); + foreach my $mount (sort keys %{$self->{logicaldisk}}) { + $self->{output}->add_disco_entry(name => $self->{logicaldisk}->{$mount}->{name}); + } +} + +1; + +__END__ + +=head1 MODE + +List Azure Computer logical disks. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/cloud/azure/management/insightsmetrics/mode/logicaldisks.pm b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/logicaldisks.pm new file mode 100644 index 000000000..4cccd84d6 --- /dev/null +++ b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/logicaldisks.pm @@ -0,0 +1,273 @@ +# +# 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 +# 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 cloud::azure::management::insightsmetrics::mode::logicaldisks; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use JSON::XS; + + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{diskSize}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{UsedSpace}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{FreeSpace}); + return sprintf( + 'total: %s used: %s (%.2f%%) free: %s (%.2f%%)', + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{UsedSpacePercentage}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{FreeSpacePercentage} + ); +} + +sub computer_long_output { + my ($self, %options) = @_; + + return "Computer '" . $options{instance_value}->{display} . "'"; +} + +sub prefix_logicaldisk_output { + my ($self, %options) = @_; + + return "'" . $options{instance_value}->{display} . "' " ; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'computer', type => 3, cb_long_output => 'computer_long_output', indent_long_output => ' ', message_multiple => 'All computers disks are OK', + group => [ + { name => 'logicaldisk', display_long => 1, cb_prefix_output => 'prefix_logicaldisk_output', message_multiple => 'All logical disks are ok', type => 1, skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{logicaldisk} = [ + { label => 'status', type => 2, critical_default => '%{status} eq "NOT OK"', set => { + key_values => [ { name => 'Status' }, { name => 'display' } ], + output_template => "status : %s", + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'usage', nlabel => 'azure.insights.logicaldisk.used.bytes', set => { + key_values => [ { name => 'UsedSpace' }, { name => 'UsedSpacePercentage' }, { name => 'FreeSpacePercentage' }, { name => 'FreeSpace' }, { name => 'diskSize'} ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', unit => 'B', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'usage-percentage', display_ok => 0, nlabel => 'azure.insights.logicaldisk.used.percentage', set => { + key_values => [ { name => 'UsedSpacePercentage' } ], + output_template => "used : %.2f%%", + perfdatas => [ + { template => '%.2f', unit => '%', min => 0, max => 100, label_extra_instance => 1 } + ] + } + }, + { label => 'free-percentage', display_ok => 0, nlabel => 'azure.insights.logicaldisk.free.percentage', set => { + key_values => [ { name => 'FreeSpacePercentage' } ], + output_template => "free : %.2f%%", + perfdatas => [ + { template => '%.2f', unit => '%', min => 0, max => 100, label_extra_instance => 1 } + ] + } + }, + { label => 'reads-persecond', nlabel => 'azure.insights.logicaldisks.io.readspersecond', set => { + key_values => [ { name => 'ReadsPerSecond' } ], + output_template => "reads per second : %.2f/s", + perfdatas => [ + { template => '%d', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'read-bytes-persecond', nlabel => 'azure.insights.logicaldisks.io.readbytespersecond', set => { + key_values => [ { name => 'ReadBytesPerSecond' } ], + output_change_bytes => 1, + output_template => "read bytes per second : %.2f/s", + perfdatas => [ + { template => '%.2f', unit => 'B/s', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'writes-persecond', nlabel => 'azure.insights.logicaldisks.io.writespersecond', set => { + key_values => [ { name => 'WritesPerSecond' } ], + output_template => "write per second : %.2f/s", + perfdatas => [ + { template => '%.2f', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'write-bytes-persecond', nlabel => 'azure.insights.logicaldisks.io.writebytespersecond', set => { + key_values => [ { name => 'WriteBytesPerSecond' } ], + output_change_bytes => 1, + output_template => "write bytes per second : %.2f/s", + perfdatas => [ + { template => '%.2f', unit => 'B/s', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'transfers-persecond', nlabel => 'azure.insights.logicaldisks.io.transferspersecond', set => { + key_values => [ { name => 'TransfersPerSecond' } ], + output_template => "transfers per second : %.2f/s", + perfdatas => [ + { template => '%.2f', min => 0, 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-computer:s' => { name => 'filter_computer' }, + 'filter-disk:s' => { name => 'filter_disk' }, + 'workspace-id:s' => { name => 'workspace_id' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + + +sub manage_selection { + my ($self, %options) = @_; + + my $query = 'InsightsMetrics | where Namespace == "LogicalDisk" | summarize arg_max(TimeGenerated, *) by Tags, Name, Computer'; + $query .= '| where Computer == "' . $self->{option_results}->{filter_computer} . '"' if defined $self->{option_results}->{filter_computer} && $self->{option_results}->{filter_computer} ne ''; + + my $results = $options{custom}->azure_get_insights_analytics( + workspace_id => $self->{option_results}->{workspace_id}, + query => $query, + timespan => $self->{option_results}->{timespan} + ); + + my $status_mapping = { + 0 => 'NOT OK', + 1 => 'OK' + }; + + my $decoded_tag; + foreach my $entry (keys %{$results->{data}}) { + $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + next if (defined($self->{option_results}->{filter_disk}) && $decoded_tag->{"vm.azm.ms\/mountId"} !~ m/$self->{option_results}->{filter_disk}/); + + if ($results->{data}->{$entry}->{tags} =~ m/\{"vm\.azm\.ms\/mountId":"(.*)"\}/) { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{logicaldisk}->{$decoded_tag->{"vm.azm.ms/mountId"}}->{display} = $decoded_tag->{"vm.azm.ms/mountId"}; + } + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{display} = $results->{data}->{$entry}->{computer}; + } + + foreach my $computer (keys %{$self->{computer}}) { + foreach my $disk (keys %{$self->{computer}->{$computer}->{logicaldisk}}) { + foreach my $entry (keys %{$results->{data}}) { + $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + my $mountid = $decoded_tag->{"vm.azm.ms/mountId"}; + next if ($mountid !~ m/$disk/); + + if ($results->{data}->{$entry}->{name} =~ m/(.*Space)MB/) { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{logicaldisk}->{$mountid}->{$1} = $results->{data}->{$entry}->{value} * 1000000; + } else { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{logicaldisk}->{$mountid}->{$results->{data}->{$entry}->{name}} = $results->{data}->{$entry}->{value}; + } + if ($results->{data}->{$entry}->{name} =~ 'Status') { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{logicaldisk}->{$mountid}->{$results->{data}->{$entry}->{name}} = %$status_mapping{$results->{data}->{$entry}->{value}}; + } + + if (defined($decoded_tag->{"vm.azm.ms/diskSizeMB"})) { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{logicaldisk}->{$mountid}->{diskSize} = $decoded_tag->{"vm.azm.ms/diskSizeMB"} * 1000000; + } + } + $self->{computer}->{$computer}->{logicaldisk}->{$disk}->{UsedSpace} = $self->{computer}->{$computer}->{logicaldisk}->{$disk}->{diskSize} - $self->{computer}->{$computer}->{logicaldisk}->{$disk}->{FreeSpace}; + $self->{computer}->{$computer}->{logicaldisk}->{$disk}->{UsedSpacePercentage} = 100 - $self->{computer}->{$computer}->{logicaldisk}->{$disk}->{FreeSpacePercentage}; + + if (scalar(keys %{$self->{computer}->{$computer}->{logicaldisk}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No logical disk found for computer " . $self->{computer}->{$computer}->{display}); + $self->{output}->option_exit(); + } + } + } + + if (scalar(keys %{$self->{computer}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No computer found. Can be: filters, cache file."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check Aure VM logical disks using Insights metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::azure::management::insightsmetrics::plugin --custommode=api --mode=logical-disks +--subscription=1111 --tenant=2222 --client-id=3333 --client-secret=4444 --workspace-id=5555 --verbose + +=over 8 + +=item B<--filter-computer> + +Filter on a specific Azure "computer". + +=item B<--filter-disk> + +Filter on specific logical(s) disk(s). + + +=item B<--warning-status> + +Warning threshold on logical disk status (Default: none). + +=item B<--critical-status> + +Critical threshold on logical disk status (Default: '%{status} eq "NOT OK"'). + +=item B<--warning-*> + +Warning threshold where '*' can be: +'usage', 'usage-percentage', 'free-percentage', 'reads-persecond', 'read-bytes-persecond', 'writes-persecond', 'write-bytes-persecond', 'transfers-persecond' + +=item B<--critical-*> + +Critical threshold where '*' can be: +'usage', 'usage-percentage', 'free-percentage', 'reads-persecond', 'read-bytes-persecond', 'writes-persecond', 'write-bytes-persecond', 'transfers-persecond' + +=back + +=cut diff --git a/centreon-plugins/cloud/azure/management/insightsmetrics/mode/memory.pm b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/memory.pm new file mode 100644 index 000000000..3a5e2fcce --- /dev/null +++ b/centreon-plugins/cloud/azure/management/insightsmetrics/mode/memory.pm @@ -0,0 +1,192 @@ +# +# 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 +# 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 cloud::azure::management::insightsmetrics::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use List::Util qw(max); +use Date::Parse; + +sub computer_long_output { + my ($self, %options) = @_; + + return "Computer '" . $options{instance_value}->{display} . "'"; +} + +sub prefix_memory_output { + my ($self, %options) = @_; + + return "Memory usage: "; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + 'Memory Total: %s %s Used: %s%s (%.2f%%) Available: %s%s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}), + $self->{result_values}->{used_prct}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{available}), + $self->{result_values}->{available_prct} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'computer', type => 3, cb_long_output => 'computer_long_output', indent_long_output => ' ', message_multiple => 'All computers CPUs are OK', + group => [ + { name => 'memory', display_long => 1, cb_prefix_output => 'prefix_memory_output', type => 0, skipped_code => { -10 => 1 } }, + ] + } + ]; + + $self->{maps_counters}->{memory} = [ + { label => 'usage', nlabel => 'azure.insights.memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'used_prct' }, { name => 'available' }, { name => 'available_prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', unit => 'B', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'usage-percentage', display_ok => 0, nlabel => 'azure.insights.memory.usage.percentage', set => { + key_values => [ { name => 'used_prct' } ], + output_template => 'used %.2f %%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 } + ] + } + }, + { label => 'available-percentage', display_ok => 0, nlabel => 'azure.insights.memory.available.percentage', set => { + key_values => [ { name => 'available_prct' } ], + output_template => 'available %.2f %%', + perfdatas => [ + { template => '%d', 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-computer:s' => { name => 'filter_computer' }, + 'workspace-id:s' => { name => 'workspace_id' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + + +sub manage_selection { + my ($self, %options) = @_; + + my $query = 'InsightsMetrics | where Namespace == "Memory" | summarize arg_max(TimeGenerated, *) by Tags, Name, Computer'; + $query .= '| where Computer == "' . $self->{option_results}->{filter_computer} . '"' if defined $self->{option_results}->{filter_computer} && $self->{option_results}->{filter_computer} ne ''; + + my $results = $options{custom}->azure_get_insights_analytics( + workspace_id => $self->{option_results}->{workspace_id}, + query => $query, + timespan => $self->{option_results}->{timespan} + ); + + my $timestamps = []; + foreach my $entry (keys %{$results->{data}}) { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{display} = $results->{data}->{$entry}->{computer}; + push @$timestamps, Date::Parse::str2time($results->{data}->{$entry}->{timegenerated}); + } + + my $decoded_tag; + foreach my $computer (keys %{$self->{computer}}) { + foreach my $entry (keys %{$results->{data}}) { + next if Date::Parse::str2time($results->{data}->{$entry}->{timegenerated}) != max(@$timestamps); + $decoded_tag = $options{custom}->json_decode(content => $results->{data}->{$entry}->{tags}); + if (defined($results->{data}->{$entry}->{value})) { + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{memory}->{available} = $results->{data}->{$entry}->{value} * 1000000; + } + $self->{computer}->{$results->{data}->{$entry}->{computer}}->{memory}->{total} = defined($decoded_tag->{"vm.azm.ms/memorySizeMB"}) ? $decoded_tag->{"vm.azm.ms/memorySizeMB"} * 1000000 : undef; + } + if (defined($self->{computer}->{$computer}->{memory}->{available}) && defined($self->{computer}->{$computer}->{memory}->{total})) { + $self->{computer}->{$computer}->{memory}->{used} = $self->{computer}->{$computer}->{memory}->{total} - + $self->{computer}->{$computer}->{memory}->{available} ; + + $self->{computer}->{$computer}->{memory}->{used_prct} = $self->{computer}->{$computer}->{memory}->{used} * 100 / $self->{computer}->{$computer}->{memory}->{total}; + $self->{computer}->{$computer}->{memory}->{available_prct} = 100 - $self->{computer}->{$computer}->{memory}->{used_prct}; + } + + if (scalar(keys %{$self->{computer}->{$computer}->{memory}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No memory found for computer " . $self->{computer}->{$computer}->{display}); + $self->{output}->option_exit(); + } + } + + if (scalar(keys %{$self->{computer}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No computer found. Can be: filters, cache file."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check Aure VM memory usage using Insights metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::azure::management::insightsmetrics::plugin --custommode=api --mode=memory +--subscription=1111 --tenant=2222 --client-id=3333 --client-secret=4444 --workspace-id=5555 --verbose + +=over 8 + +=item B<--filter-computer> + +Filter on a specific Azure "computer". + +=item B<--warning-*> + +Warning threshold where '*' can be: +'usage', 'usage-percentage', 'available-percentage' + +=item B<--critical-*> + +Critical threshold where '*' can be: +'usage', 'usage-percentage', 'available-percentage' + +=back + +=cut diff --git a/centreon-plugins/cloud/azure/management/insightsmetrics/plugin.pm b/centreon-plugins/cloud/azure/management/insightsmetrics/plugin.pm new file mode 100644 index 000000000..dc0d53c0e --- /dev/null +++ b/centreon-plugins/cloud/azure/management/insightsmetrics/plugin.pm @@ -0,0 +1,62 @@ +# +# 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 +# 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 cloud::azure::management::insightsmetrics::plugin; + +use strict; +use warnings; +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} = '1.0'; + %{$self->{modes}} = ( + 'cpu' => 'cloud::azure::management::insightsmetrics::mode::cpu', + 'list-logical-disks' => 'cloud::azure::management::insightsmetrics::mode::listlogicaldisks', + 'logical-disks' => 'cloud::azure::management::insightsmetrics::mode::logicaldisks', + 'memory' => 'cloud::azure::management::insightsmetrics::mode::memory', + ); + + $self->{custom_modes}{api} = 'cloud::azure::custom::api'; + return $self; +} + +sub init { + my ($self, %options) = @_; + + $self->{options}->add_options(arguments => { + 'api-version:s' => { name => 'api_version', default => '2018-01-01' }, + }); + + $self->SUPER::init(%options); +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Microsoft Azure Insights metrics service using Loganalytics API. + +=cut