From f7e61bb09acd477931de4a240d334b97be628821 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Thu, 10 Dec 2020 14:58:14 +0100 Subject: [PATCH] enhance commvault --- .../commvault/commserve/restapi/custom/api.pm | 1 + .../commvault/commserve/restapi/mode/jobs.pm | 26 ++- .../commserve/restapi/mode/listmediaagents.pm | 105 +++++++++++ .../restapi/mode/liststoragepolicies.pm | 105 +++++++++++ .../commserve/restapi/mode/mediaagents.pm | 176 ++++++++++++++++++ .../commvault/commserve/restapi/plugin.pm | 10 +- 6 files changed, 417 insertions(+), 6 deletions(-) create mode 100644 apps/backup/commvault/commserve/restapi/mode/listmediaagents.pm create mode 100644 apps/backup/commvault/commserve/restapi/mode/liststoragepolicies.pm create mode 100644 apps/backup/commvault/commserve/restapi/mode/mediaagents.pm diff --git a/apps/backup/commvault/commserve/restapi/custom/api.pm b/apps/backup/commvault/commserve/restapi/custom/api.pm index 147efe74d..7dd32d8ac 100644 --- a/apps/backup/commvault/commserve/restapi/custom/api.pm +++ b/apps/backup/commvault/commserve/restapi/custom/api.pm @@ -249,6 +249,7 @@ sub request_internal { $self->{output}->add_option_msg(short_msg => 'Error while retrieving data (add --debug option for detailed message)'); $self->{output}->option_exit(); } + if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { $self->{output}->add_option_msg(short_msg => 'api request error'); $self->{output}->option_exit(); diff --git a/apps/backup/commvault/commserve/restapi/mode/jobs.pm b/apps/backup/commvault/commserve/restapi/mode/jobs.pm index 727d9d951..f04820131 100644 --- a/apps/backup/commvault/commserve/restapi/mode/jobs.pm +++ b/apps/backup/commvault/commserve/restapi/mode/jobs.pm @@ -130,9 +130,11 @@ sub new { $options{options}->add_options(arguments => { 'filter-policy-name:s' => { name => 'filter_policy_name' }, + 'filter-policy-id:s' => { name => 'filter_policy_id' }, 'filter-type:s' => { name => 'filter_type' }, 'filter-client-group:s' => { name => 'filter_client_group' }, - 'filter-client-name:s' => { name => 'filter_client_name' } + 'filter-client-name:s' => { name => 'filter_client_name' }, + 'timeframe:s' => { name => 'timeframe' } }); return $self; @@ -144,15 +146,21 @@ sub manage_selection { $self->{cache_name} = 'commvault_commserve_' . $options{custom}->get_connection_infos() . '_' . $self->{mode} . '_' . (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_policy_name}) ? md5_hex($self->{option_results}->{filter_policy_name}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_policy_id}) ? md5_hex($self->{option_results}->{filter_policy_id}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_type}) ? md5_hex($self->{option_results}->{filter_type}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_client_group}) ? md5_hex($self->{option_results}->{filter_client_group}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_client_name}) ? md5_hex($self->{option_results}->{filter_client_name}) : md5_hex('all')); my $last_timestamp = $self->read_statefile_key(key => 'last_timestamp'); $last_timestamp = time() - 300 if (!defined($last_timestamp)); + my $lookup_time = time() - $last_timestamp; + if (defined($self->{option_results}->{timeframe}) && $self->{option_results}->{timeframe} =~ /(\d+)/) { + $lookup_time = $1; + } + # Also we get Pending/Waiting/Running jobs with that my $results = $options{custom}->request( - endpoint => '/Job?completedJobLookupTime=' . (time() - $last_timestamp) + endpoint => '/Job?completedJobLookupTime=' . $lookup_time ); $self->{global} = { total => 0 }; @@ -166,6 +174,7 @@ sub manage_selection { $jobs_checked->{ $job->{jobId} } = 1; my $policy_name = defined($job->{storagePolicy}->{storagePolicyName}) && $job->{storagePolicy}->{storagePolicyName} ne '' ? $job->{storagePolicy}->{storagePolicyName} : 'unknown'; + my $policy_id = defined($job->{storagePolicy}->{storagePolicyId}) && $job->{storagePolicy}->{storagePolicyId} ne '' ? $job->{storagePolicy}->{storagePolicyId} : 'unknown'; # when the job is running, end_time = 0 if (defined($self->{option_results}->{filter_policy_name}) && $self->{option_results}->{filter_policy_name} ne '' && @@ -173,6 +182,11 @@ sub manage_selection { $self->{output}->output_add(long_msg => "skipping job '" . $policy_name . "/" . $job->{jobId} . "': no matching filter.", debug => 1); next; } + if (defined($self->{option_results}->{filter_policy_id}) && $self->{option_results}->{filter_policy_id} ne '' && + $policy_id !~ /$self->{option_results}->{filter_policy_id}/) { + $self->{output}->output_add(long_msg => "skipping job '" . $policy_name . "/" . $job->{jobId} . "': no matching filter.", debug => 1); + next; + } if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && $job->{jobType} !~ /$self->{option_results}->{filter_type}/) { $self->{output}->output_add(long_msg => "skipping job '" . $policy_name . "/" . $job->{jobId} . "': no matching filter type.", debug => 1); @@ -224,6 +238,10 @@ Check jobs. Filter jobs by policy name (can be a regexp). +=item B<--filter-policy-id> + +Filter jobs by policy id (can be a regexp). + =item B<--filter-type> Filter jobs by type (can be a regexp). @@ -236,6 +254,10 @@ Filter jobs by client name (can be a regexp). Filter jobs by client groups (can be a regexp). +=item B<--timeframe> + +Set timeframe in seconds (E.g '3600' to check last 60 minutes). + =item B<--warning-status> Set warning threshold for status (Default: '%{status} =~ /abnormal/i') diff --git a/apps/backup/commvault/commserve/restapi/mode/listmediaagents.pm b/apps/backup/commvault/commserve/restapi/mode/listmediaagents.pm new file mode 100644 index 000000000..a64abffe7 --- /dev/null +++ b/apps/backup/commvault/commserve/restapi/mode/listmediaagents.pm @@ -0,0 +1,105 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::backup::commvault::commserve::restapi::mode::listmediaagents; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + return $options{custom}->request( + endpoint => '/v2/MediaAgents' + ); +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@{$results->{mediaAgentList}}) { + $self->{output}->output_add( + long_msg => sprintf( + '[id = %s][name = %s]', + $_->{mediaAgent}->{mediaAgentId}, + $_->{mediaAgent}->{mediaAgentName} + ) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List media agents:' + ); + $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 => ['id', 'name']); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@{$results->{mediaAgentList}}) { + $self->{output}->add_disco_entry( + id => $_->{mediaAgent}->{mediaAgentId}, + name => $_->{mediaAgent}->{mediaAgentName} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List media agents. + +=over 8 + +=back + +=cut + diff --git a/apps/backup/commvault/commserve/restapi/mode/liststoragepolicies.pm b/apps/backup/commvault/commserve/restapi/mode/liststoragepolicies.pm new file mode 100644 index 000000000..ca34d9e45 --- /dev/null +++ b/apps/backup/commvault/commserve/restapi/mode/liststoragepolicies.pm @@ -0,0 +1,105 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::backup::commvault::commserve::restapi::mode::liststoragepolicies; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + return $options{custom}->request( + endpoint => '/V2/StoragePolicy' + ); +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@{$results->{policies}}) { + $self->{output}->output_add( + long_msg => sprintf( + '[id = %s][name = %s]', + $_->{storagePolicy}->{storagePolicyId}, + $_->{storagePolicy}->{storagePolicyName} + ) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List storage policies:' + ); + $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 => ['id', 'name']); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@{$results->{policies}}) { + $self->{output}->add_disco_entry( + id => $_->{storagePolicy}->{storagePolicyId}, + name => $_->{storagePolicy}->{storagePolicyName} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List storage policies. + +=over 8 + +=back + +=cut + diff --git a/apps/backup/commvault/commserve/restapi/mode/mediaagents.pm b/apps/backup/commvault/commserve/restapi/mode/mediaagents.pm new file mode 100644 index 000000000..ca80e12ea --- /dev/null +++ b/apps/backup/commvault/commserve/restapi/mode/mediaagents.pm @@ -0,0 +1,176 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::backup::commvault::commserve::restapi::mode::mediaagents; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_device_status_output { + my ($self, %options) = @_; + + return sprintf( + 'status: %s [is maintenance: %s][offline reason: %s]', + $self->{result_values}->{status}, + $self->{result_values}->{is_maintenance}, + $self->{result_values}->{offline_reason} + ); +} + +sub prefix_media_output { + my ($self, %options) = @_; + + return "Media agent '" . $options{instance_value}->{name} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } }, + { name => 'medias', type => 1, cb_prefix_output => 'prefix_media_output', message_multiple => 'All media agents are ok' } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'media-agents-total', nlabel => 'media.agents.total.count', display_ok => 0, set => { + key_values => [ { name => 'agents_total' } ], + output_template => 'media agents total: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{medias} = [ + { + label => 'status', + type => 2, + critical_default => '%{is_maintenance} eq "no" and %{status} eq "offline"', + set => { + key_values => [ + { name => 'status' }, { name => 'name' }, + { name => 'is_maintenance' }, { name => 'offline_reason' } + ], + closure_custom_output => $self->can('custom_device_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +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-media-agent-id:s' => { name => 'filter_media_agent_id' }, + 'filter-media-agent-name:s' => { name => 'filter_media_agent_name' } + }); + + return $self; +} + +my $map_status = { 1 => 'online', 0 => 'offline' }; +my $map_offline_reason = { + 0 => 'default', 1 => 'connectFail', 2 => 'versionMismatch', 3 => 'markedDisabled', + 4 => 'olderVersionAndPastGraceperiod', 5 => 'initializing', 6 => 'migrated', + 7 => 'powerManagedVm', 8 => 'nodeRefreshError', 9 => 'smartStateManagement', + 10 => 'cvfwdDetectedOffline' +}; + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->request( + endpoint => '/v2/MediaAgents' + ); + + $self->{global} = { agents_total => 0 }; + $self->{medias} = {}; + foreach (@{$results->{mediaAgentList}}) { + if (defined($self->{option_results}->{filter_media_agent_id}) && $self->{option_results}->{filter_media_agent_id} ne '' && + $_->{mediaAgent}->{mediaAgentId} !~ /$self->{option_results}->{filter_media_agent_id}/) { + $self->{output}->output_add(long_msg => "skipping '" . $_->{mediaAgent}->{mediaAgentName} . "': no matching filter.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_media_agent_name}) && $self->{option_results}->{filter_media_agent_name} ne '' && + $_->{mediaAgent}->{mediaAgentName} !~ /$self->{option_results}->{filter_media_agent_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $_->{mediaAgent}->{mediaAgentName} . "': no matching filter.", debug => 1); + next; + } + + $self->{medias}->{ $_->{mediaAgent}->{mediaAgentName} } = { + name => $_->{mediaAgent}->{mediaAgentName}, + status => $map_status->{ $_->{status} }, + is_maintenance => defined($_->{mediaAgentProps}->{markMAOfflineForMaintenance}) && $_->{mediaAgentProps}->{markMAOfflineForMaintenance} =~ /True|1/i ? 'yes' : 'no', + offline_reason => $map_offline_reason->{ $_->{offlineReason} } + }; + + $self->{global}->{agents_total}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check media agents. + +=over 8 + +=item B<--filter-media-agent-id> + +Filter media agents by id (Can be a regexp). + +=item B<--filter-media-agent-name> + +Filter media agents by name (Can be a regexp). + +=item B<--unknown-device-status> + +Set unknown threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{is_maintenance}, %{offline_reason}, %{name} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{is_maintenance} eq "no" and %{status} eq "offline"'). +Can used special variables like: %{status}, %{is_maintenance}, %{offline_reason}, %{name} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'media-agents-total'. + +=back + +=cut diff --git a/apps/backup/commvault/commserve/restapi/plugin.pm b/apps/backup/commvault/commserve/restapi/plugin.pm index c1b2c7d42..036d794dd 100644 --- a/apps/backup/commvault/commserve/restapi/plugin.pm +++ b/apps/backup/commvault/commserve/restapi/plugin.pm @@ -33,10 +33,12 @@ sub new { $self->{version} = '1.0'; $self->{modes} = { - 'alerts' => 'apps::backup::commvault::commserve::restapi::mode::alerts', - 'jobs' => 'apps::backup::commvault::commserve::restapi::mode::jobs', - #'media-agents' => 'apps::backup::commvault::commserve::restapi::mode::mediaagents', - 'storage-pools' => 'apps::backup::commvault::commserve::restapi::mode::storagepools' + 'alerts' => 'apps::backup::commvault::commserve::restapi::mode::alerts', + 'jobs' => 'apps::backup::commvault::commserve::restapi::mode::jobs', + 'list-media-agents' => 'apps::backup::commvault::commserve::restapi::mode::listmediaagents', + 'list-storage-policies' => 'apps::backup::commvault::commserve::restapi::mode::liststoragepolicies', + 'media-agents' => 'apps::backup::commvault::commserve::restapi::mode::mediaagents', + 'storage-pools' => 'apps::backup::commvault::commserve::restapi::mode::storagepools' }; $self->{custom_modes}->{api} = 'apps::backup::commvault::commserve::restapi::custom::api';