From 3a49ec52063eb383b06cc7c7bd2779f6dc47ddde Mon Sep 17 00:00:00 2001 From: qgarnier Date: Tue, 19 Jan 2021 10:53:06 +0100 Subject: [PATCH] Notification jasminsms (#2527) --- .../jasminsms/httpapi/custom/api.pm | 185 ++++++++++++++++++ .../jasminsms/httpapi/mode/alert.pm | 129 ++++++++++++ .../notification/jasminsms/httpapi/plugin.pm | 49 +++++ .../os/windows/snmp/mode/service.pm | 93 +++++---- 4 files changed, 423 insertions(+), 33 deletions(-) create mode 100644 centreon-plugins/notification/jasminsms/httpapi/custom/api.pm create mode 100644 centreon-plugins/notification/jasminsms/httpapi/mode/alert.pm create mode 100644 centreon-plugins/notification/jasminsms/httpapi/plugin.pm diff --git a/centreon-plugins/notification/jasminsms/httpapi/custom/api.pm b/centreon-plugins/notification/jasminsms/httpapi/custom/api.pm new file mode 100644 index 000000000..fa42777e1 --- /dev/null +++ b/centreon-plugins/notification/jasminsms/httpapi/custom/api.pm @@ -0,0 +1,185 @@ +# +# 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 notification::jasminsms::httpapi::custom::api; + +use strict; +use warnings; +use centreon::plugins::http; + +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' }, + 'api-username:s' => { name => 'api_username' }, + 'api-password:s' => { name => 'api_password' }, + 'port:s' => { name => 'port' }, + 'proto:s' => { name => 'proto' }, + 'timeout:s' => { name => 'timeout' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostnames} = []; + if (defined($self->{option_results}->{hostname})) { + foreach my $hostname (@{$self->{option_results}->{hostname}}) { + next if ($hostname eq ''); + push @{$self->{hostnames}}, $hostname; + } + } + + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 1401; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'http'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 20; + $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} : ''; + + if (scalar(@{$self->{hostnames}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); + $self->{output}->option_exit(); + } + if ($self->{api_username} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-username option."); + $self->{output}->option_exit(); + } + if ($self->{api_password} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-password option."); + $self->{output}->option_exit(); + } + + $self->{http}->set_options(%{$self->{option_results}}); + return 0; +} + +sub send_sms { + my ($self, %options) = @_; + + my $get_param = [ + 'username=' . $self->{api_username}, + 'password=' . $self->{api_password}, + 'to=' . $options{to}, + 'coding=' . $options{coding}, + 'hex-content=' . $options{message} + ]; + if (defined($options{from}) && $options{from} ne '') { + push @$get_param, 'from=' . $options{from} + } + + my $rv = 'Error sending sms'; + my $num = scalar(@{$self->{hostnames}}); + for (my $i = 0; $i < $num; $i++) { + my ($response) = $self->{http}->request( + hostname => $self->{hostnames}->[$i], + port => $self->{port}, + proto => $self->{proto}, + url_path => '/send', + timeout => $self->{timeout}, + unknown_status => '', + warning_status => '', + critical_status => '', + get_param => $get_param + ); + if ($self->{http}->get_code() == 200) { + if ($response =~ /^Success/) { + $rv = $response; + last; + } + } else { + $rv = $response if ($response =~ /^Error/); + } + } + + return $rv; +} + +1; + +__END__ + +=head1 NAME + +Jasmin SMS HTTP-API + +=head1 HTTP API OPTIONS + +Jasmin SMS HTTP API + +=over 8 + +=item B<--hostname> + +Hostname (can be multiple if you want a failover system). + +=item B<--port> + +Port used (Default: 1401) + +=item B<--proto> + +Specify https if needed (Default: 'http') + +=item B<--api-username> + +API username. + +=item B<--api-password> + +API password. + +=item B<--timeout> + +Set timeout in seconds (Default: 20). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/centreon-plugins/notification/jasminsms/httpapi/mode/alert.pm b/centreon-plugins/notification/jasminsms/httpapi/mode/alert.pm new file mode 100644 index 000000000..26f5c05ed --- /dev/null +++ b/centreon-plugins/notification/jasminsms/httpapi/mode/alert.pm @@ -0,0 +1,129 @@ +# +# 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 notification::jasminsms::httpapi::mode::alert; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use Encode; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'from:s' => { name => 'from'}, + 'to:s' => { name => 'to' }, + 'message:s' => { name => 'message' }, + 'coding:s' => { name => 'coding', default => 8 } + }); + + return $self; +} + + +sub check_options { + my ($self, %options) = @_; + + $self->SUPER::init(%options); + if (!defined($self->{option_results}->{to}) || $self->{option_results}->{to} eq '') { + $self->{output}->add_option_msg(short_msg => 'Please set --to option'); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{coding}) || $self->{option_results}->{coding} eq '') { + $self->{option_results}->{coding} = 8; + } + $self->{option_results}->{coding} = $1 if ($self->{option_results}->{coding} =~ /(\d+)/); + if ($self->{option_results}->{coding} < 0 || $self->{option_results}->{coding} > 14) { + $self->{output}->add_option_msg(short_msg => "Please set correct --coding option [0-14]"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{message})) { + $self->{output}->add_option_msg(short_msg => 'Please set --message option'); + $self->{output}->option_exit(); + } +} + +sub encoding_message { + my ($self, %options) = @_; + + if ($self->{option_results}->{coding} == 8) { + $self->{option_results}->{message} = Encode::decode('UTF-8', $self->{option_results}->{message}); + $self->{option_results}->{message} = Encode::encode('UCS-2BE', $self->{option_results}->{message}); + } + $self->{option_results}->{message} = unpack('H*', $self->{option_results}->{message}); +} + +sub run { + my ($self, %options) = @_; + + $self->encoding_message(); + my $response = $options{custom}->send_sms( + to => $self->{option_results}->{to}, + from => $self->{option_results}->{from}, + message => $self->{option_results}->{message}, + coding => $self->{option_results}->{coding} + ); + + if ($response =~ /Error/) { + $self->{output}->add_option_msg(short_msg => $response); + $self->{output}->option_exit(); + } + + $self->{output}->output_add(short_msg => $response); + $self->{output}->display(force_ignore_perfdata => 1); + $self->{output}->exit(); +} + + +1; + +__END__ + +=head1 MODE + +Send SMS with Jasmin SMS HTTP API (https://docs.jasminsms.com/en/latest/apis/ja-http/index.html) + +=over 8 + +=item B<--from> + +Specify sender linked to account. + +=item B<--to> + +Specify receiver phone number (format 00336xxxx for French Number). + +=item B<--message> + +Specify the message to send. + +=item B<--coding> + +Sets the Data Coding Scheme bits (Default: 8 (UCS2)). + +=back + +=cut diff --git a/centreon-plugins/notification/jasminsms/httpapi/plugin.pm b/centreon-plugins/notification/jasminsms/httpapi/plugin.pm new file mode 100644 index 000000000..dfe252d47 --- /dev/null +++ b/centreon-plugins/notification/jasminsms/httpapi/plugin.pm @@ -0,0 +1,49 @@ +# +# 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 notification::jasminsms::httpapi::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} = '0.1'; + $self->{modes} = { + 'alert' => 'notification::jasminsms::httpapi::mode::alert' + }; + + $self->{custom_modes}->{api} = 'notification::jasminsms::httpapi::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Send SMS via Jasmin SMS HTTP-API. + +=cut diff --git a/centreon-plugins/os/windows/snmp/mode/service.pm b/centreon-plugins/os/windows/snmp/mode/service.pm index a226e1be9..69155930b 100644 --- a/centreon-plugins/os/windows/snmp/mode/service.pm +++ b/centreon-plugins/os/windows/snmp/mode/service.pm @@ -48,7 +48,7 @@ sub new { 'critical:s' => { name => 'critical', }, 'service:s@' => { name => 'service', }, 'regexp' => { name => 'use_regexp', }, - 'state:s' => { name => 'state', }, + 'state:s' => { name => 'state' } }); return $self; @@ -75,64 +75,91 @@ sub check_options { sub run { my ($self, %options) = @_; - $self->{snmp} = $options{snmp}; my $oid_svSvcEntry = '.1.3.6.1.4.1.77.1.2.3.1'; my $oid_svSvcInstalledState = '.1.3.6.1.4.1.77.1.2.3.1.2'; my $oid_svSvcOperatingState = '.1.3.6.1.4.1.77.1.2.3.1.3'; - my $result = $self->{snmp}->get_table(oid => $oid_svSvcEntry, start => $oid_svSvcInstalledState, end => $oid_svSvcOperatingState); + my $result = $options{snmp}->get_table(oid => $oid_svSvcEntry, start => $oid_svSvcInstalledState, end => $oid_svSvcOperatingState); - my %services_match = (); - $self->{output}->output_add(severity => 'OK', - short_msg => 'All service states are ok'); - foreach my $oid ($self->{snmp}->oid_lex_sort(keys %$result)) { - next if ($oid !~ /^$oid_svSvcOperatingState\.(.*?)\.(.*)$/); + my $services_match = {}; + $self->{output}->output_add( + severity => 'OK', + short_msg => 'All service states are ok' + ); + foreach my $oid ($options{snmp}->oid_lex_sort(keys %$result)) { + next if ($oid !~ /^$oid_svSvcOperatingState\.(\d+)\.(.*)$/); my $instance = $1 . '.' . $2; my $svc_name = $self->{output}->to_utf8(join('', map(chr($_), split(/\./, $2)))); my $svc_installed_state = $result->{$oid_svSvcInstalledState . '.' . $instance}; my $svc_operating_state = $result->{$oid_svSvcOperatingState . '.' . $instance}; for (my $i = 0; $i < scalar(@{$self->{option_results}->{service}}); $i++) { - my $filter = ${$self->{option_results}->{service}}[$i]; + $services_match->{$i} = {} if (!defined($services_match->{$i})); + my $filter = $self->{option_results}->{service}->[$i]; if (defined($self->{option_results}->{use_regexp}) && $svc_name =~ /$filter/) { - $services_match{$i}{$svc_name}{operating_state} = $svc_operating_state; - $services_match{$i}{$svc_name}{installed_state} = $svc_installed_state; + $services_match->{$i}->{$svc_name} = { + operating_state => $svc_operating_state, + installed_state => $svc_installed_state + } } elsif ($svc_name eq $filter) { - $services_match{$i}{$svc_name}{operating_state} = $svc_operating_state; - $services_match{$i}{$svc_name}{installed_state} = $svc_installed_state; + $services_match->{$i}->{$svc_name} = { + operating_state => $svc_operating_state, + installed_state => $svc_installed_state + } } } } - + for (my $i = 0; $i < scalar(@{$self->{option_results}->{service}}); $i++) { my $numbers = 0; - my %svc_name_state_wrong = (); - foreach my $svc_name (keys %{$services_match{$i}}) { - my $operating_state = $services_match{$i}{$svc_name}{operating_state}; - my $installed_state = $services_match{$i}{$svc_name}{installed_state}; - $self->{output}->output_add(long_msg => sprintf("Service '%s' match (pattern: '%s') [operating state = %s, installed state = %s]", - $svc_name, ${$self->{option_results}->{service}}[$i], - $map_operating_state{$operating_state}, $map_installed_state{$installed_state})); + my $svc_name_state_wrong = {}; + foreach my $svc_name (keys %{$services_match->{$i}}) { + my $operating_state = $services_match->{$i}->{$svc_name}->{operating_state}; + my $installed_state = $services_match->{$i}->{$svc_name}->{installed_state}; + $self->{output}->output_add(long_msg => + sprintf( + "Service '%s' match (pattern: '%s') [operating state = %s, installed state = %s]", + $svc_name, $self->{option_results}->{service}->[$i], + $map_operating_state{$operating_state}, + $map_installed_state{$installed_state} + ) + ); if (defined($self->{option_results}->{state}) && $map_operating_state{$operating_state} !~ /$self->{option_results}->{state}/) { - delete $services_match{$i}{$svc_name}; - $svc_name_state_wrong{$svc_name} = $operating_state; + delete $services_match->{$i}->{$svc_name}; + $svc_name_state_wrong->{$svc_name} = $operating_state; next; } $numbers++; } - my $exit = $self->{perfdata}->threshold_check(value => $numbers, threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(long_msg => sprintf("Service pattern '%s': service list %s", - ${$self->{option_results}->{service}}[$i], - join(', ', keys %{$services_match{$i}}))); + my $exit = $self->{perfdata}->threshold_check( + value => $numbers, threshold => [ + { label => 'critical', exit_litteral => 'critical' }, + { label => 'warning', exit_litteral => 'warning' } + ] + ); + $self->{output}->output_add( + long_msg => sprintf( + "Service pattern '%s': service list %s", + $self->{option_results}->{service}->[$i], + join(', ', keys %{$services_match->{$i}}) + ) + ); if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { - if (scalar(keys %svc_name_state_wrong) > 0) { - $self->{output}->output_add(severity => $exit, - short_msg => sprintf("Service pattern '%s' problem: %s [following services match but has the wrong state]", - ${$self->{option_results}->{service}}[$i], join(', ', keys %svc_name_state_wrong))); + if (scalar(keys %$svc_name_state_wrong) > 0) { + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf( + "Service pattern '%s' problem: %s [following services match but has the wrong state]", + $self->{option_results}->{service}->[$i], + join(', ', keys %$svc_name_state_wrong) + ) + ); } else { - $self->{output}->output_add(severity => $exit, - short_msg => sprintf("Service problem '%s'", ${$self->{option_results}->{service}}[$i])); + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf("Service problem '%s'", $self->{option_results}->{service}->[$i]) + ); } } }