centreon-plugins/notification/slack/mode/alert.pm

342 lines
14 KiB
Perl

#
# Copyright 2021 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::slack::mode::alert;
use base qw(centreon::plugins::mode);
use strict;
use warnings;
use centreon::plugins::http;
use JSON;
my %slack_color_host = (
up => 'good',
down => 'danger',
unreachable => 'danger',
);
my %slack_color_service = (
ok => 'good',
warning => 'warning',
critical => 'danger',
unknown => 'warning',
);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {
"slack-url:s" => { name => 'slack_url' },
"slack-channel:s" => { name => 'slack_channel' },
"slack-username:s" => { name => 'slack_username' },
"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' },
"slack-color:s" => { name => 'slack_color' },
"slack-emoji:s" => { name => 'slack_emoji', },
"graph-url:s" => { name => 'graph_url' },
"priority:s" => { name => 'priority' },
"zone:s" => { name => 'zone' },
"link-url:s" => { name => 'link_url' },
"centreon-url:s" => { name => 'centreon_url' },
"centreon-token:s" => { name => 'centreon_token' },
"credentials" => { name => 'credentials' },
"basic" => { name => 'basic' },
"ntlm" => { name => 'ntlm' },
"username:s" => { name => 'username' },
"password:s" => { name => 'password' },
"timeout:s" => { name => 'timeout' }
});
$self->{http} = centreon::plugins::http->new(%options);
$self->{payload_attachment} = { fields => [] };
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::init(%options);
if (!defined($self->{option_results}->{slack_url}) || $self->{option_results}->{slack_url} eq '') {
$self->{output}->add_option_msg(short_msg => "You need to specify --slack-url option.");
$self->{output}->option_exit();
}
if (!defined($self->{option_results}->{slack_channel}) || $self->{option_results}->{slack_channel} eq '') {
$self->{output}->add_option_msg(short_msg => "You need to specify --slack-channel 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}/eg;
}
}
$self->{http}->set_options(%{$self->{option_results}}, hostname => 'dummy');
}
sub format_payload {
my ($self, %options) = @_;
my $json = JSON->new;
my $payload = { channel => $self->{option_results}->{slack_channel},
attachments => [ $self->{payload_attachment} ] };
if (defined($self->{option_results}->{slack_emoji}) && $self->{option_results}->{slack_emoji} ne '') {
$payload->{icon_emoji} = $self->{option_results}->{slack_emoji};
}
if (defined($self->{option_results}->{slack_username}) && $self->{option_results}->{slack_username} ne '') {
$payload->{username} = $self->{option_results}->{slack_username};
}
eval {
$self->{payload_str} = $json->encode($payload);
};
if ($@) {
$self->{output}->add_option_msg(short_msg => "Cannot decode json response");
$self->{output}->option_exit();
}
}
sub host_message {
my ($self, %options) = @_;
my $url_host = $self->{option_results}->{host_name};
$self->{payload_attachment}->{fallback} = "Host " . $self->{option_results}->{host_name};
if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') {
$url_host = '<' . $self->{option_results}->{link_url} . '|' . $self->{option_results}->{host_name} . '>';
}
$self->{payload_attachment}->{text} = "Host " . $url_host;
if (defined($self->{option_results}->{host_state}) && $self->{option_results}->{host_state} ne '') {
$self->{payload_attachment}->{text} .= ' is ' . $self->{option_results}->{host_state};
$self->{payload_attachment}->{fallback} .= ' is ' . $self->{option_results}->{host_state};
if (defined($slack_color_host{lc($self->{option_results}->{host_state})})) {
$self->{payload_attachment}->{color} = $slack_color_host{lc($self->{option_results}->{host_state})};
}
} else {
$self->{payload_attachment}->{text} .= ' alert';
$self->{payload_attachment}->{fallback} .= ' alert';
}
if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') {
$self->{payload_attachment}->{fallback} .= ' : ' . $self->{option_results}->{link_url};
}
if (defined($self->{option_results}->{host_output}) && $self->{option_results}->{host_output} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'output', value => $self->{option_results}->{host_output}, short => 'true' };
}
if (defined($self->{option_results}->{host_state}) && $self->{option_results}->{host_state} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'State', value => $self->{option_results}->{host_state}, short => 'true'};
}
}
sub service_message {
my ($self, %options) = @_;
my $url_service = "Host: " . $self->{option_results}->{host_name} . " | Service " . $self->{option_results}->{service_description};
$self->{payload_attachment}->{fallback} = $url_service;
if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') {
$url_service = '<' . $self->{option_results}->{link_url} . '|' . $self->{option_results}->{host_name} . '/' . $self->{option_results}->{service_description} . '>';
$self->{payload_attachment}->{fallback} = "Service " . $self->{option_results}->{host_name} . '/' . $self->{option_results}->{service_description};
}
$self->{payload_attachment}->{text} = $url_service;
if (defined($self->{option_results}->{service_state}) && $self->{option_results}->{service_state} ne '') {
$self->{payload_attachment}->{text} .= ' is ' . $self->{option_results}->{service_state};
$self->{payload_attachment}->{fallback} .= ' is ' . $self->{option_results}->{service_state};
if (defined($slack_color_service{lc($self->{option_results}->{service_state})})) {
$self->{payload_attachment}->{color} = $slack_color_service{lc($self->{option_results}->{service_state})};
}
} else {
$self->{payload_attachment}->{text} .= ' alert';
$self->{payload_attachment}->{fallback} .= ' alert';
}
if (defined($self->{option_results}->{link_url}) && $self->{option_results}->{link_url} ne '') {
$self->{payload_attachment}->{fallback} .= ' : ' . $self->{option_results}->{link_url};
}
if (defined($self->{option_results}->{service_output}) && $self->{option_results}->{service_output} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'output', value => $self->{option_results}->{service_output} };
}
if (defined($self->{option_results}->{graph_url}) && $self->{option_results}->{graph_url} ne '') {
$self->{payload_attachment}->{image_url} = $self->{option_results}->{graph_url};
}
if (defined($self->{option_results}->{service_state}) && $self->{option_results}->{service_state} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'State', value => $self->{option_results}->{service_state}, short => 'true'};
}
}
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();
}
if (defined($self->{option_results}->{slack_color}) && $self->{option_results}->{slack_color} ne '') {
$self->{payload_attachment}->{color} = $self->{option_results}->{slack_color};
}
if (defined($self->{option_results}->{priority}) && $self->{option_results}->{priority} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'Priority', value => $self->{option_results}->{priority}, short => 'true' };
}
if (defined($self->{option_results}->{zone}) && $self->{option_results}->{zone} ne '') {
push @{$self->{payload_attachment}->{fields}}, { title => 'Zone', value => $self->{option_results}->{zone}, short => 'true' };
}
}
sub run {
my ($self, %options) = @_;
$self->set_payload();
$self->format_payload();
my $response = $self->{http}->request(full_url => $self->{option_results}->{slack_url},
method => 'POST',
post_param => ['payload=' . $self->{payload_str}]);
$self->{output}->output_add(short_msg => 'slack response: ' . $response);
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
1;
__END__
=head1 MODE
Send slack alerts.
Example for a host:
centreon_plugins.pl --plugin=notification::slack::plugin --mode=alert --slack-url='https://hooks.slack.com/services/T0A754E2V/B0E0CEL4B/81V8kCJusL7kafDSdsd' --slack-channel='#testchannel' --slack-username='bot' --slack-emoji=':ghost:' --host-name='srvi-clus-win' --host-state='DOWN' --host-output='test output' --priority='High' --zone='Production' --centreon-url='https://centreon.test.com/centreon/' --link-url='%{centreon_url}/main.php?p=20202&o=svc&host_search=%{host_name}'
Example for a service:
centreon_plugins.pl --plugin=notification::slack::plugin --mode=alert --slack-url='https://hooks.slack.com/services/T0A754E2V/B0E0CEL4B/81V8kCJusL7kafDSdsd' --slack-channel='#tmptestqga' --slack-username='bot' --slack-emoji=':ghost:' --host-name='srvi-clus-win' --service-description='Ping' --service-state='WARNING' --service-output='CRITICAL - 10.50.1.78: rta nan, lost 100%' --priority='High' --zone='Production' --centreon-url='https://ces.merethis.net/centreon/' --link-url='%{centreon_url}/main.php?p=20201&o=svc&host_search=%{host_name}&svc_search=%{service_description}' --centreon-token='LxTQxFbLU6' --graph-url='%{centreon_url}/include/views/graphs/generateGraphs/generateImage.php?username=myuser&token=%{centreon_token}&hostname=%{host_name}&service=%{service_description}'
=over 8
=item B<--slack-url>
Specify slack url (Required).
=item B<--slack-channel>
Specify slack channel (Required).
=item B<--slack-username>
Specify slack username.
=item B<--host-name>
Specify host server name for the alert (Required).
=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<--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<--slack-color>
Specify slack color (According state option, color will be choosed).
=item B<--slack-emoji>
Specify slack emoji.
=item B<--priority>
Specify the priority message.
=item B<--zone>
Specify the zone message.
=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<--credentials>
Specify this option if you access webpage with authentication
=item B<--username>
Specify username for authentication (Mandatory if --credentials is specified)
=item B<--password>
Specify password for authentication (Mandatory if --credentials is specified)
=item B<--basic>
Specify this option if you access webpage over basic authentication and don't want a '401 UNAUTHORIZED' error to be logged on your webserver.
Specify this option if you access webpage over hidden basic authentication or you'll get a '404 NOT FOUND' error.
(Use with --credentials)
=item B<--timeout>
Threshold for HTTP timeout (Default: 5)
=back
=cut