diff --git a/apps/cisco/cms/restapi/custom/xmlapi.pm b/apps/cisco/cms/restapi/custom/xmlapi.pm new file mode 100644 index 000000000..a2ba75e5d --- /dev/null +++ b/apps/cisco/cms/restapi/custom/xmlapi.pm @@ -0,0 +1,251 @@ +# +# Copyright 2018 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::cisco::cms::restapi::custom::xmlapi; + +use strict; +use warnings; +use centreon::plugins::http; +use XML::Simple; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => + { + "hostname:s" => { name => 'hostname' }, + "url-path:s" => { name => 'url_path' }, + "port:s" => { name => 'port' }, + "proto:s" => { name => 'proto' }, + "username:s" => { name => 'username' }, + "password:s" => { name => 'password' }, + "proxyurl:s" => { name => 'proxyurl' }, + "timeout:s" => { name => 'timeout' }, + "ssl-opt:s@" => { name => 'ssl_opt' }, + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'XMLAPI OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{mode} = $options{mode}; + $self->{http} = centreon::plugins::http->new(output => $self->{output}); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults { + my ($self, %options) = @_; + + foreach (keys %{$options{default}}) { + if ($_ eq $self->{mode}) { + for (my $i = 0; $i < scalar(@{$options{default}->{$_}}); $i++) { + foreach my $opt (keys %{$options{default}->{$_}[$i]}) { + if (!defined($self->{option_results}->{$opt}[$i])) { + $self->{option_results}->{$opt}[$i] = $options{default}->{$_}[$i]->{$opt}; + } + } + } + } + } +} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : undef; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 445; + $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} : '/api/v1'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{proxyurl} = (defined($self->{option_results}->{proxyurl})) ? $self->{option_results}->{proxyurl} : undef; + $self->{ssl_opt} = (defined($self->{option_results}->{ssl_opt})) ? $self->{option_results}->{ssl_opt} : undef; + + if (!defined($self->{option_results}->{username}) || $self->{option_results}->{username} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --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."); + $self->{output}->option_exit(); + } + + return 0; +} + +sub build_options_for_httplib { + my ($self, %options) = @_; + + $self->{option_results}->{hostname} = $self->{hostname}; + $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}->{credentials} = 1; + $self->{option_results}->{basic} = 1; + $self->{option_results}->{proxyurl} = $self->{proxyurl}; + $self->{option_results}->{warning_status} = ''; + $self->{option_results}->{critical_status} = ''; + $self->{option_results}->{unknown_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) = @_; + + return $self->{hostname}; +} + +sub get_port { + my ($self, %options) = @_; + + return $self->{port}; +} + +sub get_endpoint { + my ($self, %options) = @_; + + $self->settings; + + my $content = $self->{http}->request(url_path => $self->{url_path} . $options{method}); + my $response = $self->{http}->get_response(); + + if ($response->code() != 200) { + my $xml_result; + eval { + $xml_result = XMLin($content); + }; + 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)) { + $self->{output}->output_add(long_msg => $content, debug => 1); + $self->{output}->add_option_msg(short_msg => "Api return errors: " . join(', ', keys %{$xml_result})); + $self->{output}->option_exit(); + } + } + + my $xml_result; + eval { + $xml_result = XMLin($content, ForceArray => ['node', 'call', 'alarm'], 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(); + } + + return $xml_result; +} + +1; + +__END__ + +=head1 NAME + +Cisco CMS XML API + +=head1 SYNOPSIS + +Cisco CMS XML API + +=head1 XMLAPI OPTIONS + +=over 8 + +=item B<--hostname> + +API hostname. + +=item B<--url-path> + +API url path (Default: '/api/v1') + +=item B<--port> + +API port (Default: 445) + +=item B<--proto> + +Specify https if needed (Default: 'https') + +=item B<--username> + +Set API username + +=item B<--password> + +Set API password + +=item B<--proxyurl> + +Proxy URL if any + +=item B<--timeout> + +Set HTTP timeout + +=item B<--ssl-opt> + +Set SSL options if needed (--ssl-opt="SSL_version => TLSv1" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/apps/cisco/cms/restapi/mode/alarms.pm b/apps/cisco/cms/restapi/mode/alarms.pm new file mode 100644 index 000000000..612cc80f2 --- /dev/null +++ b/apps/cisco/cms/restapi/mode/alarms.pm @@ -0,0 +1,198 @@ +# +# Copyright 2018 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::cisco::cms::restapi::mode::alarms; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use centreon::plugins::statefile; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("alarm '%s' active for %s", + $self->{result_values}->{type}, centreon::plugins::misc::change_seconds(value => $self->{result_values}->{active_time})); + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{type} = $options{new_datas}->{$self->{instance} . '_type'}; + $self->{result_values}->{active_time} = $options{new_datas}->{$self->{instance} . '_activeTimeSeconds'}; + return 0; +} + + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'alarms', type => 2, message_multiple => '0 problem(s) detected', display_counter_problem => { label => 'alerts', min => 0 }, + group => [ { name => 'alarm', skipped_code => { -11 => 1 } } ] + } + ]; + + $self->{maps_counters}->{alarm} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'type' }, { name => 'activeTimeSeconds' } ], + 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 => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "filter-type:s" => { name => 'filter_type' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, + "memory" => { name => 'memory' }, + }); + + $self->{statefile_cache} = centreon::plugins::statefile->new(%options); + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $instance_mode = $self; + $self->change_macros(); + if (defined($self->{option_results}->{memory})) { + $self->{statefile_cache}->check_options(%options); + } +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{alarms}->{global} = { alarm => {} }; + + my $results = $options{custom}->get_endpoint(method => '/system/alarms'); + + my $last_time; + if (defined($self->{option_results}->{memory})) { + $self->{statefile_cache}->read(statefile => "cache_cisco_cms_" . $options{custom}->get_hostname() . '_' . $options{custom}->get_port(). '_' . $self->{mode}); + $last_time = $self->{statefile_cache}->get(name => 'last_time'); + } + + my ($i, $current_time) = (1, time()); + foreach my $alarm (@{$results->{alarm}}) { + my $create_time = $current_time - $alarm->{activeTimeSeconds}; + + next if (defined($self->{option_results}->{memory}) && defined($last_time) && $last_time > $create_time); + if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && + $alarm->{type} !~ /$self->{option_results}->{filter_type}/) { + $self->{output}->output_add(long_msg => "skipping '" . $alarm->{type} . "': no matching filter.", debug => 1); + next; + } + + my $diff_time = $current_time - $create_time; + + $self->{alarms}->{global}->{alarm}->{$i} = { %$alarm, since => $diff_time }; + $i++; + } + + if (defined($self->{option_results}->{memory})) { + $self->{statefile_cache}->write(data => { last_time => $current_time }); + } +} + +1; + +__END__ + +=head1 MODE + +Check alarms. + +=over 8 + +=item B<--filter-type> + +Filter by type (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{type}, %{active_time} + +=item B<--critical-status> + +Set critical threshold for status (Default: ''). +Can used special variables like: %{type}, %{active_time} + +=item B<--memory> + +Only check new alarms. + +=back + +=cut diff --git a/apps/cisco/cms/restapi/mode/calls.pm b/apps/cisco/cms/restapi/mode/calls.pm new file mode 100644 index 000000000..736d11d7e --- /dev/null +++ b/apps/cisco/cms/restapi/mode/calls.pm @@ -0,0 +1,140 @@ +# +# Copyright 2018 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::cisco::cms::restapi::mode::calls; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 }, + ]; + + $self->{maps_counters}->{global} = [ + { label => 'active-calls', set => { + key_values => [ { name => 'calls' } ], + output_template => 'Active calls: %d', + perfdatas => [ + { label => 'active_calls', value => 'calls_absolute', template => '%d', + min => 0, unit => 'calls' }, + ], + } + }, + { label => 'local-participants', set => { + key_values => [ { name => 'numParticipantsLocal' } ], + output_template => 'Local participants: %d', + perfdatas => [ + { label => 'local_participants', value => 'numParticipantsLocal_absolute', template => '%d', + min => 0, unit => 'participants' }, + ], + } + }, + { label => 'remote-participants', set => { + key_values => [ { name => 'numParticipantsRemote' } ], + output_template => 'Remote participants: %d', + perfdatas => [ + { label => 'remote_participants', value => 'numParticipantsRemote_absolute', template => '%d', + min => 0, unit => 'participants' }, + ], + } + }, + { label => 'call-legs', set => { + key_values => [ { name => 'numCallLegs' } ], + output_template => 'Call legs: %d', + perfdatas => [ + { label => 'call_legs', value => 'numCallLegs_absolute', template => '%d', + min => 0, unit => 'legs' }, + ], + } + }, + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "filter-counters:s" => { name => 'filter_counters' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->get_endpoint(method => '/calls'); + + $self->{global} = { calls => 0, numParticipantsLocal => 0, numParticipantsRemote => 0 , numCallLegs => 0 }; + + $self->{global}->{calls} = $results->{total}; + + foreach my $call (@{$results->{call}}) { + my $result = $options{custom}->get_endpoint(method => '/calls/' . $call->{id}); + $self->{global}->{numParticipantsLocal} += $result->{numParticipantsLocal}; + $self->{global}->{numParticipantsRemote} += $result->{numParticipantsRemote}; + $self->{global}->{numCallLegs} += $result->{numCallLegs}; + } +} + +1; + +__END__ + +=head1 MODE + +Check number of calls and participants. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +(Example: --filter-counters='calls') + +=item B<--warning-*> + +Threshold warning. +Can be: 'active-calls', 'local-participants', 'remote-participants', +'call-legs'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'active-calls', 'local-participants', 'remote-participants', +'call-legs'. + +=back + +=cut diff --git a/apps/cisco/cms/restapi/mode/databasestatus.pm b/apps/cisco/cms/restapi/mode/databasestatus.pm new file mode 100644 index 000000000..1001ec398 --- /dev/null +++ b/apps/cisco/cms/restapi/mode/databasestatus.pm @@ -0,0 +1,180 @@ +# +# Copyright 2018 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::cisco::cms::restapi::mode::databasestatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("master status is '%s', up is '%s' [Sync behind: %s B]", + $self->{result_values}->{master}, $self->{result_values}->{up}, $self->{result_values}->{sync_behind}); + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{sync_behind} = $options{new_datas}->{$self->{instance} . '_syncBehind'}; + $self->{result_values}->{master} = $options{new_datas}->{$self->{instance} . '_master'}; + $self->{result_values}->{up} = $options{new_datas}->{$self->{instance} . '_up'}; + $self->{result_values}->{hostname} = $options{new_datas}->{$self->{instance} . '_hostname'}; + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'nodes', type => 1, cb_prefix_output => 'prefix_node_output', message_multiple => 'All database hosts are ok' }, + ]; + + $self->{maps_counters}->{nodes} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'syncBehind' }, { name => 'master' }, { name => 'up' }, + { name => 'hostname' } ], + 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 => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub prefix_node_output { + my ($self, %options) = @_; + + return "Node '" . $options{instance_value}->{hostname} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{up} !~ /true/i' }, + }); + + return $self; +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $instance_mode = $self; + $self->change_macros(); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->get_endpoint(method => '/system/database'); + + $self->{nodes} = {}; + + if (defined($results->{clustered}) && $results->{clustered} ne 'enabled' ) { + $self->{output}->add_option_msg(short_msg => "Database clustering is not enabled"); + $self->{output}->option_exit(); + } + + foreach my $node (@{$results->{cluster}->{node}}) { + $self->{nodes}->{$node->{hostname}} = { + hostname => $node->{hostname}, + master => $node->{master}, + up => $node->{up}, + syncBehind => $node->{syncBehind}, + }; + } + + if (scalar(keys %{$self->{nodes}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No nodes found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check database status. + +=over 8 + +=item B<--warning-status> + +Set warning threshold for status. (Default: ''). +Can use special variables like: %{hostname}, %{master}, %{up}, %{sync_behind} + +=item B<--critical-status> + +Set critical threshold for status. (Default: '%{up} !~ /true/i'). +Can use special variables like: %{hostname}, %{master}, %{up}, %{sync_behind} + +=back + +=cut diff --git a/apps/cisco/cms/restapi/mode/licenses.pm b/apps/cisco/cms/restapi/mode/licenses.pm new file mode 100644 index 000000000..0df844a2d --- /dev/null +++ b/apps/cisco/cms/restapi/mode/licenses.pm @@ -0,0 +1,182 @@ +# +# Copyright 2018 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::cisco::cms::restapi::mode::licenses; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use DateTime; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("status is '%s'", $self->{result_values}->{status}); + $msg .= sprintf(", expires in %d days [%s]", + $self->{result_values}->{expiry_days}, + $self->{result_values}->{expiry_date}) if (defined($self->{result_values}->{expiry_date}) && $self->{result_values}->{expiry_date} ne ''); + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{feature} = $options{new_datas}->{$self->{instance} . '_feature'}; + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; + $self->{result_values}->{expiry_date} = $options{new_datas}->{$self->{instance} . '_expiry_date'}; + $self->{result_values}->{expiry_seconds} = $options{new_datas}->{$self->{instance} . '_expiry_timestamp'} - time(); + $self->{result_values}->{expiry_days} = $self->{result_values}->{expiry_seconds} / 86400; + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'features', type => 1, cb_prefix_output => 'prefix_feature_output', message_multiple => 'All features licensing are ok' }, + ]; + + $self->{maps_counters}->{features} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'feature' }, { name => 'status' }, { name => 'expiry_date' }, { name => 'expiry_timestamp' } ], + 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 => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub prefix_feature_output { + my ($self, %options) = @_; + + return "Feature '" . $options{instance_value}->{feature} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "warning-status:s" => { name => 'warning_status', default => '%{expiry_days} < 60' }, + "critical-status:s" => { name => 'critical_status', default => '%{expiry_days} < 30' }, + }); + + return $self; +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $instance_mode = $self; + $self->change_macros(); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->get_endpoint(method => '/system/licensing'); + + $self->{features} = {}; + + foreach my $feature (keys %{$results->{features}}) { + my %months = ("Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12); + $results->{features}->{$feature}->{expiry} =~ /^(\d+)-(\w+)-(\d+)$/ if (defined($results->{features}->{$feature}->{expiry})); # 2100-Jan-01 + my $dt = DateTime->new(year => $1, month => $months{$2}, day => $3); + + $self->{features}->{$feature} = { + feature => $feature, + status => $results->{features}->{$feature}->{status}, + expiry_date => (defined($results->{features}->{$feature}->{expiry})) ? $results->{features}->{$feature}->{expiry} : '', + expiry_timestamp => (defined($results->{features}->{$feature}->{expiry})) ? $dt->epoch : '', + }; + } + + if (scalar(keys %{$self->{features}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No features found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check features licensing. + +=over 8 + +=item B<--warning-status> + +Set warning threshold for status. (Default: '%{expiry_days} < 60'). +Can use special variables like: %{status}, %{expiry_days}, %{feature} + +=item B<--critical-status> + +Set critical threshold for status. (Default: '%{expiry_days} < 30'). +Can use special variables like: %{status}, %{expiry_days}, %{feature} + +=back + +=cut diff --git a/apps/cisco/cms/restapi/mode/systemstatus.pm b/apps/cisco/cms/restapi/mode/systemstatus.pm new file mode 100644 index 000000000..35650779c --- /dev/null +++ b/apps/cisco/cms/restapi/mode/systemstatus.pm @@ -0,0 +1,263 @@ +# +# Copyright 2018 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::cisco::cms::restapi::mode::systemstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("Call Bridge activation is '%s', cluster enabled is '%s'", + $self->{result_values}->{activated}, $self->{result_values}->{cluster_enabled}); + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{activated} = $options{new_datas}->{$self->{instance} . '_activated'}; + $self->{result_values}->{cluster_enabled} = $options{new_datas}->{$self->{instance} . '_clusterEnabled'}; + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 }, + { name => 'legs', type => 0, cb_prefix_output => 'prefix_leg_output', skipped_code => { -10 => 1 } }, + { name => 'rates', type => 0, cb_prefix_output => 'prefix_rate_output', skipped_code => { -10 => 1 } }, + ]; + + $self->{maps_counters}->{global} = [ + { label => 'status', set => { + key_values => [ { name => 'activated' }, { name => 'clusterEnabled' } ], + 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 => $self->can('custom_status_threshold'), + } + }, + ]; + $self->{maps_counters}->{legs} = [ + { label => 'active-legs', set => { + key_values => [ { name => 'callLegsActive' } ], + output_template => 'Active: %d', + perfdatas => [ + { label => 'active_legs', value => 'callLegsActive_absolute', template => '%d', + min => 0, unit => 'legs' }, + ], + } + }, + { label => 'completed-legs', set => { + key_values => [ { name => 'callLegsCompleted' } ], + output_template => 'Completed: %d', + perfdatas => [ + { label => 'completed_legs', value => 'callLegsCompleted_absolute', template => '%d', + min => 0, unit => 'legs' }, + ], + } + }, + ]; + $self->{maps_counters}->{rates} = [ + { label => 'audio-outgoing-rate', set => { + key_values => [ { name => 'audioBitRateOutgoing' } ], + output_template => 'outgoing audio streams: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'audio_outgoing_rate', value => 'audioBitRateOutgoing_absolute', template => '%d', + min => 0, unit => 'b/s' }, + ], + } + }, + { label => 'audio-incoming-rate', set => { + key_values => [ { name => 'audioBitRateIncoming' } ], + output_template => 'incoming audio streams: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'audio_incoming_rate', value => 'audioBitRateIncoming_absolute', template => '%d', + min => 0, unit => 'b/s' }, + ], + } + }, + { label => 'video-outgoing-rate', set => { + key_values => [ { name => 'videoBitRateOutgoing' } ], + output_template => 'outgoing video streams: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'video_outgoing_rate', value => 'videoBitRateOutgoing_absolute', template => '%d', + min => 0, unit => 'b/s' }, + ], + } + }, + { label => 'video-incoming-rate', set => { + key_values => [ { name => 'videoBitRateIncoming' } ], + output_template => 'incoming video streams: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'video_incoming_rate', value => 'videoBitRateIncoming_absolute', template => '%d', + min => 0, unit => 'b/s' }, + ], + } + }, + ]; +} + +sub prefix_leg_output { + my ($self, %options) = @_; + + return "Legs "; +} + +sub prefix_rate_output { + my ($self, %options) = @_; + + return "Rates "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "filter-counters:s" => { name => 'filter_counters' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{activated} !~ /true/i' }, + }); + + return $self; +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $instance_mode = $self; + $self->change_macros(); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->get_endpoint(method => '/system/status'); + + $self->{global} = ''; + $self->{legs} = ''; + $self->{rates} = ''; + + $self->{global} = { + activated => $results->{activated}, + clusterEnabled => $results->{clusterEnabled}, + }; + $self->{legs} = { + callLegsActive => $results->{callLegsActive}, + callLegsCompleted => $results->{callLegsCompleted}, + }; + $self->{rates} = { + audioBitRateOutgoing => $results->{audioBitRateOutgoing}, + audioBitRateIncoming => $results->{audioBitRateIncoming}, + videoBitRateOutgoing => $results->{videoBitRateOutgoing}, + videoBitRateIncoming => $results->{videoBitRateIncoming}, + }; +} + +1; + +__END__ + +=head1 MODE + +Check system status. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +(Example: --filter-counters='rate') + +=item B<--warning-status> + +Set warning threshold for status. (Default: ''). +Can use special variables like: %{activated}, %{cluster_enabled} + +=item B<--critical-status> + +Set critical threshold for status. (Default: '%{activated} !~ /true/i'). +Can use special variables like: %{activated}, %{cluster_enabled} + +=item B<--warning-*> + +Threshold warning. +Can be: 'active-legs', 'completed-legs', 'audio-outgoing-rate', +'audio-incoming-rate', 'video-outgoing-rate', 'video-incoming-rate'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'active-legs', 'completed-legs', 'audio-outgoing-rate', +'audio-incoming-rate', 'video-outgoing-rate', 'video-incoming-rate'. + +=back + +=cut diff --git a/apps/cisco/cms/restapi/plugin.pm b/apps/cisco/cms/restapi/plugin.pm new file mode 100644 index 000000000..83f1bc2f0 --- /dev/null +++ b/apps/cisco/cms/restapi/plugin.pm @@ -0,0 +1,52 @@ +# +# Copyright 2018 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::cisco::cms::restapi::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}} = ( + 'alarms' => 'apps::cisco::cms::restapi::mode::alarms', + 'calls' => 'apps::cisco::cms::restapi::mode::calls', + 'database-status' => 'apps::cisco::cms::restapi::mode::databasestatus', + 'licenses' => 'apps::cisco::cms::restapi::mode::licenses', + 'system-status' => 'apps::cisco::cms::restapi::mode::systemstatus', + ); + $self->{custom_modes}{api} = 'apps::cisco::cms::restapi::custom::xmlapi'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Cisco Meeting Server (CMS) API. + +=cut