From 9cbe0dabbdb86840e8fa4d535727aea0aeeaa970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Pilpr=C3=A9?= Date: Mon, 10 Dec 2018 14:53:07 +0100 Subject: [PATCH] Telegram Notification (#1266) * First Release of Telegram Notification Plugin * Minor esthetical code modification * Code Beautify * changes after code review --- notification/telegram/mode/alert.pm | 291 ++++++++++++++++++++++++++++ notification/telegram/plugin.pm | 48 +++++ 2 files changed, 339 insertions(+) create mode 100644 notification/telegram/mode/alert.pm create mode 100644 notification/telegram/plugin.pm diff --git a/notification/telegram/mode/alert.pm b/notification/telegram/mode/alert.pm new file mode 100644 index 000000000..bc0c447f5 --- /dev/null +++ b/notification/telegram/mode/alert.pm @@ -0,0 +1,291 @@ +# +# 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 notification::telegram::mode::alert; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use centreon::plugins::http; +use JSON::XS; + +my %telegram_icon_host = ( + up => "\x{2705}", + down => "\x{1F525}", + unreachable => "\x{2753}", +); +my %telegram_icon_service = ( + ok => "\x{2705}", + warning => "\x{26A0}", + critical => "\x{1F525}", + unknown => "\x{2753}", +); + +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 => + { + "hostname:s" => { name => 'hostname', default => 'api.telegram.org' }, + "port:s" => { name => 'port', default => 443 }, + "proto:s" => { name => 'proto', default => 'https' }, + "urlpath:s" => { name => 'url_path', default => "/sendMessage" }, + "chat-id:s" => { name => 'chat_id' }, + "bot-token:s" => { name => 'bot_token' }, + "host-name:s" => { name => 'host_name' }, + "host-state:s" => { name => 'host_state' }, + "host-output:s" => { name => 'host_output' }, + "service-description:s" => { name => 'service_description' }, + "service-state:s" => { name => 'service_state' }, + "service-output:s" => { name => 'service_output' }, + "graph-url:s" => { name => 'graph_url' }, + "link-url:s" => { name => 'link_url' }, + "centreon-url:s" => { name => 'centreon_url' }, + "centreon-token:s" => { name => 'centreon_token' }, + "proxyurl:s" => { name => 'proxyurl' }, + "proxypac:s" => { name => 'proxypac' }, + "timeout:s" => { name => 'timeout' }, + "ssl-opt:s@" => { name => 'ssl_opt' }, + }); + + $self->{http} = centreon::plugins::http->new(output => $self->{output}); + return $self; +} + +sub check_options { + my ($self, %options) = @_; + + $self->SUPER::init(%options); + if (!defined($self->{option_results}->{chat_id})) { + $self->{output}->add_option_msg(short_msg => "You need to set --chat-id option"); + $self->{output}->option_exit(); + } + if (!defined($self->{option_results}->{bot_token})) { + $self->{output}->add_option_msg(short_msg => "You need to set --bot-token option"); + $self->{output}->option_exit(); + } + if (!defined($self->{option_results}->{host_name}) || $self->{option_results}->{host_name} eq '') { + $self->{output}->add_option_msg(short_msg => "You need to specify --host-name option."); + $self->{output}->option_exit(); + } + + foreach (('graph_url', 'link_url')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{option_results}->{$1}/g; + eval "\$self->{option_results}->{\$_} = \"$self->{option_results}->{$_}\""; + } + } + + $self->{http}->set_options(%{$self->{option_results}}); +} + +sub host_message { + my ($self, %options) = @_; + + if (defined($self->{option_results}->{host_state}) && $self->{option_results}->{host_state} ne '') { + if (defined($telegram_icon_host{lc($self->{option_results}->{host_state})})) { + $self->{message} = $telegram_icon_host{lc($self->{option_results}->{host_state})}; + } + } + + $self->{message} .= " Host " . $self->{option_results}->{host_name} . ""; + + if (defined($self->{option_results}->{host_state}) && $self->{option_results}->{host_state} ne '') { + $self->{message} .= ' is ' . $self->{option_results}->{host_state} . ''; + } else { + $self->{message} .= ' alert'; + } + + if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') { + $self->{message} .= "\n {option_results}->{link_url} . "\">Link"; + } +} + +sub service_message { + my ($self, %options) = @_; + + if (defined($self->{option_results}->{service_state}) && $self->{option_results}->{service_state} ne '') { + if (defined($telegram_icon_service{lc($self->{option_results}->{service_state})})) { + $self->{message} = $telegram_icon_service{lc($self->{option_results}->{service_state})}; + } + } + + $self->{message} .= " Host " . $self->{option_results}->{host_name} . " | Service " . $self->{option_results}->{service_description} . ""; + + if (defined($self->{option_results}->{service_state}) && $self->{option_results}->{service_state} ne '') { + $self->{message} .= ' is ' . $self->{option_results}->{service_state} . ''; + } else { + $self->{message} .= ' alert'; + } + if (defined($self->{option_results}->{service_output}) && $self->{option_results}->{service_output} ne '') { + $self->{message} .= "\n ". $self->{option_results}->{service_output}; + } + if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') { + $self->{message} .= "\n {option_results}->{link_url} . "\">Link"; + } + if (defined($self->{option_results}->{graph_url}) && $self->{option_results}->{graph_url} ne '') { + $self->{message} .= "\n {option_results}->{graph_url} . "\">Graph"; + } +} + +sub set_payload { + my ($self, %options) = @_; + + if (defined($self->{option_results}->{service_description}) && $self->{option_results}->{service_description} ne '') { + $self->service_message(); + } else { + $self->host_message(); + } +} + +sub format_payload { + my ($self, %options) = @_; + + my $json = JSON::XS->new->utf8; + + my $payload = { chat_id =>$self->{option_results}->{chat_id}, + parse_mode => 'HTML', + text => $self->{message} }; + eval { + $self->{payload_str} = $json->encode($payload); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot encode json request"); + $self->{output}->option_exit(); + } +} + + +sub run { + my ($self, %options) = @_; + + $self->{http}->add_header(key => 'Content-Type', value => 'application/json'); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + + $self->set_payload(); + $self->format_payload(); + + my $url_path = '/bot' . $self->{option_results}->{bot_token} . $self->{option_results}->{url_path}; + my $response = $self->{http}->request(url_path => $url_path, + method => 'POST', query_form_post => $self->{payload_str}); + + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($response); + }; + if ($@) { + $self->{output}->output_add(long_msg => $response, debug => 1); + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + if (!defined($decoded->{result}->{message_id})) { + $self->{output}->output_add(long_msg => $decoded, debug => 1); + $self->{output}->add_option_msg(short_msg => "Error sending message"); + $self->{output}->option_exit(); + } + + $self->{output}->output_add(short_msg => 'Message ID : ' . $decoded->{result}->{message_id}); + $self->{output}->display(force_ignore_perfdata => 1); + $self->{output}->exit(); +} + +1; + +__END__ + +=head1 MODE + +Send message with Telegram API. + +=over 6 + +=item B<--chat-id> + +Telegram Chat ID (Negative Integer for Group) +Use Telegram CLI for getting Chat ID + +=item B<--bot-token> + +Telegram Bot Token (Check Telegram Doc for Creating Bot) +https://core.telegram.org/bots#3-how-do-i-create-a-bot + +=item B<--proxyurl> + +Proxy URL if any. + +=item B<--proxypac> + +Proxy pac file (can be an url or local file). + +=item B<--host-state> + +Specify host server state for the alert. + +=item B<--host-output> + +Specify host server output message for the alert. + +=item B<--host-name> + +Specify host server name for the alert (Required). + +=item B<--service-description> + +Specify service description name for the alert. + +=item B<--service-state> + +Specify service state for the alert. + +=item B<--service-output> + +Specify service output message for the alert. + +=item B<--centreon-url> + +Specify the centreon url macro (could be used in link-url and graph-url option). + +=item B<--centreon-token> + +Specify the centreon token for autologin macro (could be used in link-url and graph-url option). + +=item B<--graph-url> + +Specify the graph url (Example: %{centreon_url}/include/views/graphs/generateGraphs/generateImage.php?username=myuser&token=%{centreon_token}&hostname=%{host_name}&service=%{service_description}). + +=item B<--link-url> + +Specify the link url (Example: %{centreon_url}/main.php?p=20201&o=svc&host_search=%{host_name}&svc_search=%{service_description}) + +=item B<--timeout> + +Threshold for HTTP timeout. + +=item B<--ssl-opt> + +Set SSL Options (--ssl-opt="SSL_version => TLSv1" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). + +=back + +=cut diff --git a/notification/telegram/plugin.pm b/notification/telegram/plugin.pm new file mode 100644 index 000000000..fa87db322 --- /dev/null +++ b/notification/telegram/plugin.pm @@ -0,0 +1,48 @@ +# +# 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 notification::telegram::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_simple); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + %{$self->{modes}} = ( + 'alert' => 'notification::telegram::mode::alert', + ); + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Send Telegram notifications. + +=cut