diff --git a/network/cisco/vcs/restapi/custom/xmlapi.pm b/network/cisco/vcs/restapi/custom/xmlapi.pm index 39ce743db..32b1fcf27 100644 --- a/network/cisco/vcs/restapi/custom/xmlapi.pm +++ b/network/cisco/vcs/restapi/custom/xmlapi.pm @@ -23,7 +23,7 @@ package network::cisco::vcs::restapi::custom::xmlapi; use strict; use warnings; use centreon::plugins::http; -use XML::Simple; +use XML::LibXML::Simple; sub new { my ($class, %options) = @_; @@ -41,13 +41,15 @@ sub new { if (!defined($options{noptions})) { $options{options}->add_options(arguments => { - 'hostname:s' => { name => 'hostname' }, - 'url-path:s' => { name => 'url_path' }, - 'port:s' => { name => 'port' }, - 'proto:s' => { name => 'proto' }, - 'username:s' => { name => 'username' }, - 'password:s' => { name => 'password' }, - 'timeout:s' => { name => 'timeout' } + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port' }, + 'proto:s' => { name => 'proto' }, + 'api-username:s' => { name => 'api_username' }, + 'api-password:s' => { name => 'api_password' }, + 'timeout:s' => { name => 'timeout' }, + 'unknown-http-status:s' => { name => 'unknown_http_status' }, + 'warning-http-status:s' => { name => 'warning_http_status' }, + 'critical-http-status:s' => { name => 'critical_http_status' } }); } $options{options}->add_help(package => __PACKAGE__, sections => 'XMLAPI OPTIONS', once => 1); @@ -69,24 +71,26 @@ sub set_defaults {} sub check_options { my ($self, %options) = @_; - $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : undef; + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; - $self->{username} = (defined($self->{option_results}->{username})) ? $self->{option_results}->{username} : undef; - $self->{password} = (defined($self->{option_results}->{password})) ? $self->{option_results}->{password} : undef; - $self->{url_path} = (defined($self->{option_results}->{url_path})) ? $self->{option_results}->{url_path} : '/getxml?location='; - $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{api_username} = (defined($self->{option_results}->{api_username})) ? $self->{option_results}->{api_username} : ''; + $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 20; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; - if (!defined($self->{option_results}->{hostname}) || $self->{option_results}->{hostname} eq '') { + if ($self->{hostname} eq '') { $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); $self->{output}->option_exit(); } - if (!defined($self->{option_results}->{username}) || $self->{option_results}->{username} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify --username option."); + if ($self->{api_username} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-username option."); $self->{output}->option_exit(); } - if (!defined($self->{option_results}->{password}) || $self->{option_results}->{password} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify --password option."); + if ($self->{api_password} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-password option."); $self->{output}->option_exit(); } @@ -100,28 +104,19 @@ sub build_options_for_httplib { $self->{option_results}->{timeout} = $self->{timeout}; $self->{option_results}->{port} = $self->{port}; $self->{option_results}->{proto} = $self->{proto}; - $self->{option_results}->{username} = $self->{username}; - $self->{option_results}->{password} = $self->{password}; + $self->{option_results}->{username} = $self->{api_username}; + $self->{option_results}->{password} = $self->{api_password}; $self->{option_results}->{credentials} = 1; $self->{option_results}->{basic} = 1; - $self->{option_results}->{warning_status} = ''; - $self->{option_results}->{critical_status} = ''; } sub settings { my ($self, %options) = @_; $self->build_options_for_httplib(); - $self->{http}->set_options(%{$self->{option_results}}); } -sub get_connection_info { - my ($self, %options) = @_; - - return $self->{hostname} . ":" . $self->{port}; -} - sub get_hostname { my ($self, %options) = @_; @@ -137,21 +132,23 @@ sub get_port { sub get_endpoint { my ($self, %options) = @_; - $self->settings; - - my $content = $self->{http}->request(url_path => $self->{url_path} . $options{method}); + $self->settings(); + my $content = $self->{http}->request( + url_path => $options{endpoint}, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); my $xml_result; eval { - $xml_result = XMLin($content, ForceArray => ['Call', 'Zone'], KeyAttr => []); + $xml_result = XMLin($content, ForceArray => $options{force_array}, KeyAttr => []); }; if ($@) { - $self->{output}->output_add(long_msg => $content, debug => 1); $self->{output}->add_option_msg(short_msg => "Cannot decode xml response: $@"); $self->{output}->option_exit(); } if (defined($xml_result->{XPathError})) { - $self->{output}->output_add(long_msg => $content, debug => 1); $self->{output}->add_option_msg(short_msg => "Api return error: " . $xml_result->{XPathError}->{Reason}); $self->{output}->option_exit(); } @@ -179,10 +176,6 @@ Cisco VCS XML API API hostname. -=item B<--url-path> - -API url path (Default: '/getxml?location=') - =item B<--port> API port (Default: 443) @@ -191,11 +184,11 @@ API port (Default: 443) Specify https if needed (Default: 'https') -=item B<--username> +=item B<--api-username> Set API username -=item B<--password> +=item B<--api-password> Set API password diff --git a/network/cisco/vcs/restapi/mode/calls.pm b/network/cisco/vcs/restapi/mode/calls.pm index d8c20dc7d..8913dc776 100644 --- a/network/cisco/vcs/restapi/mode/calls.pm +++ b/network/cisco/vcs/restapi/mode/calls.pm @@ -24,158 +24,140 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); +use Date::Parse; +use Digest::MD5 qw(md5_hex); -sub custom_status_output { +sub prefix_global_output { my ($self, %options) = @_; - my $msg = sprintf("state is '%s' [Duration: %s s]", - $self->{result_values}->{state}, $self->{result_values}->{duration}); - return $msg; -} - -sub custom_status_calc { - my ($self, %options) = @_; - - $self->{result_values}->{serial_number} = $options{new_datas}->{$self->{instance} . '_SerialNumber'}; - $self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_State'}; - $self->{result_values}->{duration} = $options{new_datas}->{$self->{instance} . '_Duration'}; - return 0; + return 'Calls '; } 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 => 'calls', type => 1, cb_prefix_output => 'prefix_call_output', message_multiple => 'All calls are ok' }, + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } } ]; $self->{maps_counters}->{global} = [ - { label => 'traversal', set => { - key_values => [ { name => 'Traversal' } ], - output_template => 'Traversal: %d', - perfdatas => [ - { label => 'traversal', value => 'Traversal', template => '%d', - min => 0, unit => 'calls' }, - ], + { label => 'dummy', threshold => 0, display_ok => 0, set => { + key_values => [ { name => 'last_cdr_start_time' } ], + output_template => 'none', + perfdatas => [] } - }, - { label => 'non-traversal', set => { - key_values => [ { name => 'NonTraversal' } ], - output_template => 'Non Traversal: %d', - perfdatas => [ - { label => 'non_traversal', value => 'NonTraversal', template => '%d', - min => 0, unit => 'calls' }, - ], - } - }, - { label => 'collaboration-edge', set => { - key_values => [ { name => 'CollaborationEdge' } ], - output_template => 'Collaboration Edge: %d', - perfdatas => [ - { label => 'collaboration_edge', value => 'CollaborationEdge', template => '%d', - min => 0, unit => 'calls' }, - ], - } - }, - { label => 'cloud', set => { - key_values => [ { name => 'Cloud' } ], - output_template => 'Cloud: %d', - perfdatas => [ - { label => 'cloud', value => 'Cloud', template => '%d', - min => 0, unit => 'calls' }, - ], - } - }, - { label => 'microsoft-content', set => { - key_values => [ { name => 'MicrosoftContent' } ], - output_template => 'Microsoft Content: %d', - perfdatas => [ - { label => 'microsoft_content', value => 'MicrosoftContent', template => '%d', - min => 0, unit => 'calls' }, - ], - } - }, - { label => 'microsoft-imp', set => { - key_values => [ { name => 'MicrosoftIMP' } ], - output_template => 'Microsoft IMP: %d', - perfdatas => [ - { label => 'microsoft_imp', value => 'MicrosoftIMP', template => '%d', - min => 0, unit => 'calls' }, - ], - } - }, + } ]; - $self->{maps_counters}->{calls} = [ - { label => 'status', set => { - key_values => [ { name => 'State' }, { name => 'Duration' }, { name => 'SerialNumber' } ], - closure_custom_calc => $self->can('custom_status_calc'), - closure_custom_output => $self->can('custom_status_output'), - closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold, - } - }, - ]; -} -sub prefix_global_output { - my ($self, %options) = @_; + foreach (( + ['traversal', 1, 'traversal'], ['nontraversal', 1, 'non traversal'], + ['cloud', 1, 'cloud'], ['collaborationedge', 0, 'collaboration edge'], + ['microsoftcontent', 0, 'microsoft content'], ['microsoftimp', 0, 'microsoft imp'] + )) { + push @{$self->{maps_counters}->{global}}, + { + label => $_->[0] . '-current', nlabel => 'calls.' . $_->[0] . '.current.count', display_ok => $_->[1], set => { + key_values => [ { name => $_->[0] . '_current' } ], + output_template => $_->[2] . ' current: %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }, + { + label => $_->[0] . '-total', nlabel => 'calls.' . $_->[0] . '.total.count', display_ok => 0, set => { + key_values => [ { name => $_->[0] . '_total', diff => 1 } ], + output_template => $_->[2] . ' total: %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }; + } - return "Number of Calls "; -} - -sub prefix_call_output { - my ($self, %options) = @_; - - return "Call '" . $options{instance_value}->{SerialNumber} . "' "; + foreach (( + ['connectionfailed', 1, 'connection failed'], ['disconnected', 1, 'disconnected'] + )) { + push @{$self->{maps_counters}->{global}}, { + label => $_->[0] . '-total', nlabel => 'calls.' . $_->[0] . '.total.count', display_ok => $_->[1], set => { + key_values => [ { name => $_->[0] } ], + output_template => $_->[2] . ': %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }; + } } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); bless $self, $class; - $options{options}->add_options(arguments => - { - "warning-status:s" => { name => 'warning_status' }, - "critical-status:s" => { name => 'critical_status', default => '%{state} ne "Connected"' }, - }); + $options{options}->add_options(arguments => { + }); return $self; } -sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - $self->change_macros(macros => ['warning_status', 'critical_status']); -} - sub manage_selection { my ($self, %options) = @_; - my $usages = $options{custom}->get_endpoint(method => '/Status/ResourceUsage/Calls'); + $self->{cache_name} = 'cisco_vcs_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); - $self->{global}->{Traversal} = $usages->{ResourceUsage}->{Calls}->{Traversal}->{Current}->{content}; - $self->{global}->{NonTraversal} = $usages->{ResourceUsage}->{Calls}->{NonTraversal}->{Current}->{content}; - $self->{global}->{CollaborationEdge} = $usages->{ResourceUsage}->{Calls}->{CollaborationEdge}->{Current}->{content}; - $self->{global}->{Cloud} = $usages->{ResourceUsage}->{Calls}->{Cloud}->{Current}->{content}; - $self->{global}->{MicrosoftContent} = $usages->{ResourceUsage}->{Calls}->{MicrosoftContent}->{Current}->{content}; - $self->{global}->{MicrosoftIMP} = $usages->{ResourceUsage}->{Calls}->{MicrosoftIMP}->{Current}->{content}; + my $calls = $options{custom}->get_endpoint( + endpoint => '/getxml?location=/Status/ResourceUsage/Calls' + ); - my $results = $options{custom}->get_endpoint(method => '/Status/Calls'); + $self->{global} = { + traversal_current => $calls->{ResourceUsage}->{Calls}->{Traversal}->{Current}->{content}, + traversal_total => $calls->{ResourceUsage}->{Calls}->{Traversal}->{Total}->{content}, + nontraversal_current => $calls->{ResourceUsage}->{Calls}->{NonTraversal}->{Current}->{content}, + nontraversal_total => $calls->{ResourceUsage}->{Calls}->{NonTraversal}->{Total}->{content}, + cloud_current => $calls->{ResourceUsage}->{Calls}->{Cloud}->{Current}->{content}, + cloud_total => $calls->{ResourceUsage}->{Calls}->{Cloud}->{Total}->{content}, + collaborationedge_current => $calls->{ResourceUsage}->{Calls}->{CollaborationEdge}->{Current}->{content}, + collaborationedge_total => $calls->{ResourceUsage}->{Calls}->{CollaborationEdge}->{Total}->{content}, + microsoftcontent_current => $calls->{ResourceUsage}->{Calls}->{MicrosoftContent}->{Current}->{content}, + microsoftcontent_total => $calls->{ResourceUsage}->{Calls}->{MicrosoftContent}->{Total}->{content}, + microsoftimp_current => $calls->{ResourceUsage}->{Calls}->{MicrosoftIMP}->{Current}->{content}, + microsoftimp_total => $calls->{ResourceUsage}->{Calls}->{MicrosoftIMP}->{Total}->{content}, + connectionfailed => 0, + disconnected => 0 + }; - $self->{calls} = {}; + my $last_cdr_start_time = $self->read_statefile_key(key => 'global_last_cdr_start_time'); + $last_cdr_start_time = 0 if (!defined($last_cdr_start_time)); + my $results = $options{custom}->get_endpoint( + endpoint => '/history.xml?location=/Calls', + force_array => ['Call'] + ); + + #2020-09-24 12:28:52.267179 + my $max_start_time = $last_cdr_start_time; foreach my $call (@{$results->{Calls}->{Call}}) { - next if (!defined($call->{SerialNumber})); - $self->{calls}->{$call->{SerialNumber}->{content}} = { - SerialNumber => $call->{SerialNumber}->{content}, - Duration => $call->{Duration}->{content}, - State => $call->{State}->{content}, - }; + my $tmp_time = Date::Parse::str2time($call->{StartTime}->{content}); + if (!defined($tmp_time)) { + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => "can't parse date '" . $call->{StartTime}->{content} . "'" + ); + next; + } + + $tmp_time = int($tmp_time * 10000); + $max_start_time = $tmp_time if ($max_start_time < $tmp_time); + if ($tmp_time > $last_cdr_start_time) { + $call->{State}->{content} =~ s/\s+//g; + $self->{global}->{ lc($call->{State}->{content}) }++ + if (defined($self->{global}->{ lc($call->{State}->{content}) })); + } } + + $self->{global}->{last_cdr_start_time} = $max_start_time; } 1; @@ -184,31 +166,20 @@ __END__ =head1 MODE -Check calls count and state. +Check current calls and history. =over 8 -=item B<--warning-*> +=item B<--warning-*> B<--critical-*> -Threshold warning. -Can be: 'traversal', 'non-traversal', 'collaboration-edge', -'cloud', 'microsoft-content', 'microsoft-imp'. - -=item B<--critical-*> - -Threshold critical. -Can be: 'traversal', 'non-traversal', 'collaboration-edge', -'cloud', 'microsoft-content', 'microsoft-imp'. - -=item B<--warning-status> - -Set warning threshold for status. (Default: ''). -Can use special variables like: %{state}, %{serial_number}, %{duration}. - -=item B<--critical-status> - -Set critical threshold for status. (Default: '%{state} ne "Connected"'). -Can use special variables like: %{state}, %{serial_number}, %{duration}. +Thresholds. +Can be: 'traversal-current', 'traversal-total', +'nontraversal-current', 'nontraversal-total', +'cloud-current', 'cloud-total', ' +'collaborationedge-current', 'collaborationedge-total', +'microsoftcontent-current', 'microsoftcontent-total', +'microsoftimp-current', 'microsoftimp-total', +'connectionfailed-total', 'disconnected-total'. =back diff --git a/network/cisco/vcs/restapi/mode/httpproxystats.pm b/network/cisco/vcs/restapi/mode/httpproxystats.pm index 405356ab0..158e35560 100644 --- a/network/cisco/vcs/restapi/mode/httpproxystats.pm +++ b/network/cisco/vcs/restapi/mode/httpproxystats.pm @@ -25,20 +25,33 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; use Digest::MD5 qw(md5_hex); -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); sub custom_status_output { my ($self, %options) = @_; - my $msg = sprintf("Status is '%s'", $self->{result_values}->{status}); - return $msg; + return sprintf( + "http proxy status is '%s'", + $self->{result_values}->{status} + ); } -sub custom_status_calc { +sub prefix_connections_output { my ($self, %options) = @_; - $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_Status'}; - return 0; + return 'Connections '; +} + +sub prefix_requests_output { + my ($self, %options) = @_; + + return 'Resquests '; +} + +sub prefix_responses_output { + my ($self, %options) = @_; + + return 'Responses '; } sub set_counters { @@ -48,170 +61,150 @@ sub set_counters { { name => 'global', type => 0 }, { name => 'connections', type => 0, cb_prefix_output => 'prefix_connections_output' }, { name => 'requests', type => 0, cb_prefix_output => 'prefix_requests_output' }, - { name => 'responses', type => 0, cb_prefix_output => 'prefix_responses_output' }, + { name => 'responses', type => 0, cb_prefix_output => 'prefix_responses_output' } ]; $self->{maps_counters}->{global} = [ - { label => 'status', set => { - key_values => [ { name => 'Status' } ], - closure_custom_calc => $self->can('custom_status_calc'), + { label => 'status', type => 2, critical_default => '%{status} ne "Active"',set => { + key_values => [ { name => 'status' } ], closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold, + closure_custom_threshold_check => \&catalog_status_threshold_ng } - }, + } ]; + $self->{maps_counters}->{connections} = [ - { label => 'client-connections', set => { - key_values => [ { name => 'TotalClientConnection', per_second => 1 } ], - output_template => 'Client: %.2f/s', + { label => 'connections-client', nlabel => 'httproxy.connections.client.persecond', set => { + key_values => [ { name => 'total_client_connection', per_second => 1 } ], + output_template => 'client: %.2f/s', perfdatas => [ - { label => 'client_connections', template => '%.2f', min => 0, unit => 'connections/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'server-connections', set => { - key_values => [ { name => 'TotalServerConnection', per_second => 1 } ], - output_template => 'Server: %.2f/s', + { label => 'connections-server', nlabel => 'httproxy.connections.server.persecond', set => { + key_values => [ { name => 'total_server_connection', per_second => 1 } ], + output_template => 'server: %.2f/s', perfdatas => [ - { label => 'server_connections', template => '%.2f', min => 0, unit => 'connections/s' }, - ], + { template => '%.2f', min => 0 } + ] } } ]; $self->{maps_counters}->{requests} = [ - { label => 'completed-requests', set => { - key_values => [ { name => 'CompletedRequests', per_second => 1 } ], - output_template => 'Completed: %.2f/s', + { label => 'requests-completed', nlabel => 'httproxy.requests.completed.persecond', set => { + key_values => [ { name => 'completed', per_second => 1 } ], + output_template => 'completed: %.2f/s', perfdatas => [ - { label => 'completed_requests', template => '%.2f', min => 0, unit => 'requests/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'get-requests', set => { - key_values => [ { name => 'GetRequests', per_second => 1 } ], - output_template => 'Get: %.2f/s', + { label => 'requests-get', nlabel => 'httproxy.requests.get.persecond', set => { + key_values => [ { name => 'get', per_second => 1 } ], + output_template => 'get: %.2f/s', perfdatas => [ - { label => 'get_requests', template => '%.2f', min => 0, unit => 'requests/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'post-requests', set => { - key_values => [ { name => 'PostRequests', per_second => 1 } ], - output_template => 'Post: %.2f/s', + { label => 'requests-post', nlabel => 'httproxy.requests.post.persecond', set => { + key_values => [ { name => 'post', per_second => 1 } ], + output_template => 'post: %.2f/s', perfdatas => [ - { label => 'post_requests', template => '%.2f', min => 0, unit => 'requests/s' }, - ], + { template => '%.2f', min => 0 } + ] } } ]; $self->{maps_counters}->{responses} = [ - { label => 'responses-1xx', set => { - key_values => [ { name => 'Response1XXCount', per_second => 1 } ], - output_template => '1XX: %.2f/s', + { label => 'responses-1xx', nlabel => 'httproxy.responses.1xx.persecond', set => { + key_values => [ { name => 'response1xxx', per_second => 1 } ], + output_template => '1xx: %.2f/s', perfdatas => [ - { label => 'responses_1xx', template => '%.2f', min => 0, unit => 'responses/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'responses-2xx', set => { - key_values => [ { name => 'Response2XXCount', per_second => 1 } ], - output_template => '2XX: %.2f/s', + { label => 'responses-2xx', nlabel => 'httproxy.responses.2xx.persecond', set => { + key_values => [ { name => 'response2xxx', per_second => 1 } ], + output_template => '2xx: %.2f/s', perfdatas => [ - { label => 'responses_2xx', template => '%.2f', min => 0, unit => 'responses/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'responses-3xx', set => { - key_values => [ { name => 'Response3XXCount', per_second => 1 } ], - output_template => '3XX: %.2f/s', + { label => 'responses-3xx', nlabel => 'httproxy.responses.3xx.persecond', set => { + key_values => [ { name => 'response3xxx', per_second => 1 } ], + output_template => '3xx: %.2f/s', perfdatas => [ - { label => 'responses_3xx', template => '%.2f', min => 0, unit => 'responses/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'responses-4xx', set => { - key_values => [ { name => 'Response4XXCount', per_second => 1 } ], - output_template => '4XX: %.2f/s', + { label => 'responses-4xx', nlabel => 'httproxy.responses.4xx.persecond', set => { + key_values => [ { name => 'response4xxx', per_second => 1 } ], + output_template => '4xx: %.2f/s', perfdatas => [ - { label => 'responses_4xx', template => '%.2f', min => 0, unit => 'responses/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'responses-5xx', set => { - key_values => [ { name => 'Response5XXCount', per_second => 1 } ], - output_template => '5XX: %.2f/s', + { label => 'responses-5xx', nlabel => 'httproxy.responses.5xx.persecond', set => { + key_values => [ { name => 'response5xxx', per_second => 1 } ], + output_template => '5xx: %.2f/s', perfdatas => [ - { label => 'responses_5xx', template => '%.2f', min => 0, unit => 'responses/s' }, - ], + { template => '%.2f', min => 0 } + ] } - }, + } ]; } -sub prefix_connections_output { - my ($self, %options) = @_; - - return "Connections "; -} - -sub prefix_requests_output { - my ($self, %options) = @_; - - return "Resquests "; -} - -sub prefix_responses_output { - my ($self, %options) = @_; - - return "Responses "; -} - sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { - 'warning-status:s' => { name => 'warning_status' }, - 'critical-status:s' => { name => 'critical_status', default => '%{status} ne "Active"' } }); return $self; } -sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - $self->change_macros(macros => ['warning_status', 'critical_status']); -} - sub manage_selection { my ($self, %options) = @_; - my $results = $options{custom}->get_endpoint(method => '/Status/HTTPProxy'); + my $results = $options{custom}->get_endpoint( + endpoint => '/getxml?location=/Status/HTTPProxy' + ); - $self->{global} = {}; - $self->{connections} = {}; - $self->{requests} = {}; - $self->{responses} = {}; + $self->{global} = { + status => $results->{HTTPProxy}->{Status}->{content} + }; + if (defined($results->{HTTPProxy}->{Stats})) { + $self->{connections} = { + total_client_connection => $results->{HTTPProxy}->{Stats}->{TotalClientConnection}->{content}, + total_server_connection => $results->{HTTPProxy}->{Stats}->{TotalServerConnection}->{content} + }; + $self->{requests} = { + completed => $results->{HTTPProxy}->{Stats}->{CompletedRequests}->{content}, + get => $results->{HTTPProxy}->{Stats}->{GetRequests}->{content}, + post => $results->{HTTPProxy}->{Stats}->{PostRequests}->{content} + }; + $self->{responses} = { + response1xxx => $results->{HTTPProxy}->{Stats}->{Response1XXCount}->{content}, + response2xxx => $results->{HTTPProxy}->{Stats}->{Response2XXCount}->{content}, + response3xxx => $results->{HTTPProxy}->{Stats}->{Response3XXCount}->{content}, + response4xxx => $results->{HTTPProxy}->{Stats}->{Response4XXCount}->{content}, + response5xxx => $results->{HTTPProxy}->{Stats}->{Response5XXCount}->{content} + }; + } - $self->{global}->{Status} = $results->{HTTPProxy}->{Status}->{content}; - $self->{connections}->{TotalClientConnection} = $results->{HTTPProxy}->{Stats}->{TotalClientConnection}->{content}; - $self->{connections}->{TotalServerConnection} = $results->{HTTPProxy}->{Stats}->{TotalServerConnection}->{content}; - $self->{requests}->{CompletedRequests} = $results->{HTTPProxy}->{Stats}->{CompletedRequests}->{content}; - $self->{requests}->{GetRequests} = $results->{HTTPProxy}->{Stats}->{GetRequests}->{content}; - $self->{requests}->{PostRequests} = $results->{HTTPProxy}->{Stats}->{PostRequests}->{content}; - $self->{responses}->{Response1XXCount} = $results->{HTTPProxy}->{Stats}->{Response1XXCount}->{content}; - $self->{responses}->{Response2XXCount} = $results->{HTTPProxy}->{Stats}->{Response2XXCount}->{content}; - $self->{responses}->{Response3XXCount} = $results->{HTTPProxy}->{Stats}->{Response3XXCount}->{content}; - $self->{responses}->{Response4XXCount} = $results->{HTTPProxy}->{Stats}->{Response4XXCount}->{content}; - $self->{responses}->{Response5XXCount} = $results->{HTTPProxy}->{Stats}->{Response5XXCount}->{content}; - - $self->{cache_name} = "cisco_vcs_" . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . $self->{mode} . '_' . + $self->{cache_name} = 'cisco_vcs_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . $self->{mode} . '_' . (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); } @@ -230,28 +223,21 @@ Check HTTP proxy status and statistics. Only display some counters (regexp can be used). (Example: --filter-counters='responses') -=item B<--warning-*> +=item B<--warning-*> B<--critical-*> -Threshold warning (/s). -Can be: 'client-connections', 'server-connections', 'completed-requests', -'get-requests', 'post-requests', 'responses-1xx', 'responses-2xx', -'responses-3xx', 'responses-4xx', 'responses-5xx'. - -=item B<--critical-*> - -Threshold critical (/s). -Can be: 'client-connections', 'server-connections', 'completed-requests', -'get-requests', 'post-requests', 'responses-1xx', 'responses-2xx', -'responses-3xx', 'responses-4xx', 'responses-5xx'. +Threshold. +Can be: 'connections-client', 'connections-server', +'requests-completed', 'requests-get', 'requests-post', +'responses-1xx', 'responses-2xx', 'responses-3xx', 'responses-4xx', 'responses-5xx'. =item B<--warning-status> -Set warning threshold for status. (Default: ''). +Set warning threshold for status. Can use special variables like: %{status}. =item B<--critical-status> -Set critical threshold for status. (Default: '%{status} ne "Active"'). +Set critical threshold for status (Default: '%{status} ne "Active"'). Can use special variables like: %{status}. =back diff --git a/network/cisco/vcs/restapi/mode/zones.pm b/network/cisco/vcs/restapi/mode/zones.pm index fa5fdfc8a..616fb3dce 100644 --- a/network/cisco/vcs/restapi/mode/zones.pm +++ b/network/cisco/vcs/restapi/mode/zones.pm @@ -25,14 +25,15 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; use Digest::MD5 qw(md5_hex); -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); sub custom_status_output { my ($self, %options) = @_; - my $msg = sprintf("Status is '%s' [Type: %s]", - $self->{result_values}->{status}, $self->{result_values}->{type}); - return $msg; + return sprintf( + "status is '%s' [type: %s]", + $self->{result_values}->{status}, $self->{result_values}->{type} + ); } sub custom_status_calc { @@ -44,142 +45,143 @@ sub custom_status_calc { return 0; } +sub prefix_searches_output { + my ($self, %options) = @_; + + return 'Searches '; +} + +sub prefix_zones_output { + my ($self, %options) = @_; + + return "Zone '" . $options{instance_value}->{name} . "' "; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ { name => 'global', type => 0}, { name => 'searches', type => 0, cb_prefix_output => 'prefix_searches_output' }, - { name => 'zones', type => 1, cb_prefix_output => 'prefix_zones_output', message_multiple => 'All zones are ok' }, + { name => 'zones', type => 1, cb_prefix_output => 'prefix_zones_output', message_multiple => 'All zones are ok' } ]; $self->{maps_counters}->{global} = [ - { label => 'zones-count', set => { + { label => 'zones-count', nlabel => 'zones.total.count', set => { key_values => [ { name => 'count' } ], output_template => 'Number of zones: %d', perfdatas => [ - { label => 'zones_count', template => '%d', min => 0 } + { template => '%d', min => 0 } ] } } ]; $self->{maps_counters}->{searches} = [ - { label => 'searches-total', set => { - key_values => [ { name => 'Total', per_second => 1 } ], - output_template => 'Total: %.2f/s', + { label => 'searches-total', nlabel => 'zones.searches.total.persecond', set => { + key_values => [ { name => 'total', per_second => 1 } ], + output_template => 'total: %.2f/s', perfdatas => [ - { label => 'searches_total', template => '%.2f', min => 0, unit => 'searches/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'searches-dropped', set => { - key_values => [ { name => 'Dropped', per_second => 1 } ], - output_template => 'Dropped: %.2f/s', + { label => 'searches-dropped', nlabel => 'zones.searches.dropped.persecond', set => { + key_values => [ { name => 'dropped', per_second => 1 } ], + output_template => 'dropped: %.2f/s', perfdatas => [ - { label => 'searches_dropped', template => '%.2f', min => 0, unit => 'searches/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'searches-max-sub-search-exceeded', set => { - key_values => [ { name => 'MaxSubSearchExceeded', per_second => 1 } ], - output_template => 'Max Sub Search Exceeded: %.2f/s', + { label => 'searches-maxsub-exceeded', nlabel => 'zones.searches.maxsub.exceeded.count', set => { + key_values => [ { name => 'max_sub_search_exceeded', diff => 1 } ], + output_template => 'max sub exceeded: %s', perfdatas => [ - { label => 'searches_max_sub_search_exceeded', template => '%.2f', - min => 0, unit => 'searches/s' }, - ], + { template => '%.2f', min => 0 } + ] } }, - { label => 'searches-max-targets-exceeded', set => { - key_values => [ { name => 'MaxTargetsExceeded', per_second => 1 } ], - output_template => 'Max Targets Exceeded: %.2f/s', + { label => 'searches-maxtargets-exceeded', nlabel => 'zones.searches.maxtargets.exceeded.count', set => { + key_values => [ { name => 'max_targets_exceeded', diff => 1 } ], + output_template => 'max targets exceeded: %s', perfdatas => [ - { label => 'searches_max_targets_exceeded', template => '%.2f', min => 0, unit => 'searches/s' }, - ], + { template => '%s', min => 0 } + ] } } ]; $self->{maps_counters}->{zones} = [ - { label => 'status', set => { - key_values => [ { name => 'Status' }, { name => 'Type' }, { name => 'Name' } ], - closure_custom_calc => $self->can('custom_status_calc'), + { label => 'status', type => 2, critical_default => '%{status} ne "Active"', set => { + key_values => [ { name => 'status' }, { name => 'type' }, { name => 'name' } ], closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold + closure_custom_threshold_check => \&catalog_status_threshold_ng } }, - { label => 'calls-count', set => { - key_values => [ { name => 'Calls' }, { name => 'Name' } ], - output_template => 'Number of Calls: %d', + { label => 'zone-calls-current', nlabel => 'zone.calls.current.count', set => { + key_values => [ { name => 'calls' } ], + output_template => 'current calls: %d', perfdatas => [ - { label => 'calls_count', template => '%d', min => 0, label_extra_instance => 1, instance_use => 'Name' } + { template => '%d', min => 0, label_extra_instance => 1 } ] } } ]; } -sub prefix_searches_output { - my ($self, %options) = @_; - - return "Searches "; -} - -sub prefix_zones_output { - my ($self, %options) = @_; - - return "Zone '" . $options{instance_value}->{Name} . "' "; -} - sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { - 'warning-status:s' => { name => 'warning_status' }, - 'critical-status:s' => { name => 'critical_status', default => '%{status} ne "Active"' } + 'filter-zone-name:s' => { name => 'filter_zone_name' } }); return $self; } -sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - $self->change_macros(macros => ['warning_status', 'critical_status']); -} - sub manage_selection { my ($self, %options) = @_; - my $results = $options{custom}->get_endpoint(method => '/Status/Zones'); + my $results = $options{custom}->get_endpoint( + endpoint => '/getxml?location=/Status/Zones', + force_array => ['Zone', 'Call'] + ); $self->{global}->{count} = 0; - $self->{searches} = {}; - $self->{zones} = {}; - - $self->{searches}->{Total} = $results->{Zones}->{Searches}->{Total}->{content}; - $self->{searches}->{Dropped} = $results->{Zones}->{Searches}->{Dropped}->{content}; - $self->{searches}->{MaxSubSearchExceeded} = $results->{Zones}->{Searches}->{MaxSubSearchExceeded}->{content}; - $self->{searches}->{MaxTargetsExceeded} = $results->{Zones}->{Searches}->{MaxTargetsExceeded}->{content}; + $self->{searches} = { + total => $results->{Zones}->{Searches}->{Total}->{content}, + dropped => $results->{Zones}->{Searches}->{Dropped}->{content}, + max_sub_search_exceeded => $results->{Zones}->{Searches}->{MaxSubSearchExceeded}->{content}, + max_targets_exceeded => $results->{Zones}->{Searches}->{MaxTargetsExceeded}->{content} + }; + $self->{zones} = {}; foreach my $zone (@{$results->{Zones}->{Zone}}) { next if (!defined($zone->{Name})); - $self->{zones}->{$zone->{Name}->{content}} = { - Type => $zone->{Type}->{content}, - Name => $zone->{Name}->{content}, - Calls => (defined($zone->{Calls})) ? scalar(@{$zone->{Calls}->{Call}}) : 0, - Status => $zone->{Status}->{content}, + + if (defined($self->{option_results}->{filter_zone_name}) && $self->{option_results}->{filter_zone_name} ne '' && + $zone->{Name}->{content} !~ /$self->{option_results}->{filter_zone_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $zone->{Name}->{content} . "': no matching filter vserver.", debug => 1); + next; + } + + $self->{zones}->{ $zone->{Name}->{content} } = { + type => $zone->{Type}->{content}, + name => $zone->{Name}->{content}, + calls => (defined($zone->{Calls})) ? scalar(@{$zone->{Calls}->{Call}}) : 0, + status => $zone->{Status}->{content} }; $self->{global}->{count}++; } - $self->{cache_name} = "cisco_vcs_" . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . $self->{mode} . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); + $self->{cache_name} = 'cisco_vcs_' . $options{custom}->get_hostname() . '_' . $options{custom}->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_zone_name}) ? md5_hex($self->{option_results}->{filter_zone_name}) : md5_hex('all')) } 1; @@ -188,21 +190,19 @@ __END__ =head1 MODE -Check zones count and state. +Check zones. =over 8 -=item B<--warning-*> +=item B<--filter-zone-name> -Threshold warning. -Can be: 'zones-count', 'calls-count', 'searches-total' (/s), 'searches-dropped' (/s), -'searches-max-sub-search-exceeded' (/s), 'searches-max-targets-exceeded' (/s). +Filter zones by name (can be a regexp). -=item B<--critical-*> +=item B<--warning-*> B<--critical-*> -Threshold critical. -Can be: 'zones-count', 'calls-count', 'searches-total' (/s), 'searches-dropped' (/s), -'searches-max-sub-search-exceeded' (/s), 'searches-max-targets-exceeded' (/s). +Thresholds. +Can be: 'zones-count', 'zone-calls-current', 'searches-total', +'searches-dropped', 'searches-maxsub-exceeded', 'searches-maxtargets-exceeded'. =item B<--warning-status> diff --git a/network/cisco/vcs/restapi/plugin.pm b/network/cisco/vcs/restapi/plugin.pm index 7341480c0..0db336550 100644 --- a/network/cisco/vcs/restapi/plugin.pm +++ b/network/cisco/vcs/restapi/plugin.pm @@ -30,13 +30,13 @@ sub new { bless $self, $class; $self->{version} = '1.0'; - %{$self->{modes}} = ( + $self->{modes} = { 'calls' => 'network::cisco::vcs::restapi::mode::calls', 'http-proxy-stats' => 'network::cisco::vcs::restapi::mode::httpproxystats', - 'zones' => 'network::cisco::vcs::restapi::mode::zones', - ); + 'zones' => 'network::cisco::vcs::restapi::mode::zones' + }; - $self->{custom_modes}{xmlapi} = 'network::cisco::vcs::restapi::custom::xmlapi'; + $self->{custom_modes}->{xmlapi} = 'network::cisco::vcs::restapi::custom::xmlapi'; return $self; }