Commit a8811766 authored by Matthieu Muffato's avatar Matthieu Muffato
Browse files

Integration to Slack (Runnable + beekeeper)

parent 8265f2eb
......@@ -40,6 +40,7 @@ Developer tools:
* An experimental "Unicode-art" flow diagram drawing code has been implemented (skip the -output parameter in generate_graph.pl to see)
* eHive's DBAdaptor now has methods to get the list of eHive tables and views
* standaloneJob test method: warnings can be assessed via a regular expression
* Support for Slack WebHook integrations in beekeeper and a dedicated Runnable
Under the hood:
* HivePipeline object with its collections becomes the center of things, and TheApiary becomes the centralized way of accessing foreign objects
......
How to connect eHive to Slack
=============================
---------
> With this tutorial, our goal is to explain how to configure eHive and Slack
to be able to report messages to a Slack channel.
> First of all, you obviously need to have a Slack team. You or someone else
will have to be allowed to configure Apps.
---------
1. Let's first add the "Incoming WebHooks" app to your team
1. In the main Slack menu select "Apps & Custom Integrations"
2. Find "Incoming WebHooks" via the search box and select it
3. You should be on a page that gives an introduction about WebHooks and
lists the teams you belong too. Somebody may have already configured some
WebHooks for your team.
1. If it is the case, click on the "Configure" button next to your team
name and then "Add Configuration"
2. Otherwise, click on the "Install" button next to your team name
2. Let's now configure a webhook to use with eHive
1. You first need to choose the channel eHive will write too. Although
the Slack API allows to override the channel and thus use a single webhook
to post to different channels, we advice to configure 1 webhook per channel
2. Click "Add Incoming WebHooks Integration"
3. The page now shows advanced configuration for the integration. The most
important here is the "Webhook URL". This is what eHive needs
4. If you scroll down to "Integration Settings" you can give a description
for the WebHook, change its name and emoji. Note that the latter can be
overriden in the Runnable SlackNotification
3. Use the WebHook in eHive
1. Define the `EHIVE_SLACK_WEBHOOK` environment variable when running your
beekeepe
2. Configure the `slack_webhook` parameter in the SlackNotification Runnable
=pod
=head1 NAME
Bio::EnsEMBL::Hive::RunnableDB::SlackNotification
=head1 SYNOPSIS
This is a RunnableDB module that implements Bio::EnsEMBL::Hive::Process interface
and is ran by Workers during the execution of eHive pipelines.
It is not generally supposed to be instantiated and used outside of this framework.
Please refer to Bio::EnsEMBL::Hive::Process documentation to understand the basics of the RunnableDB interface.
Please refer to Bio::EnsEMBL::Hive::PipeConfig::* pipeline configuration files to understand how to configure pipelines.
=head1 DESCRIPTION
This RunnableDB module will send a notification to a Slack channel.
You can either dataflow into it, or simply create standalone jobs.
It requires "slack_webhook" to be defined. You can this in the parameters of your Slack team.
The message itself is defined by the "text" parameter (and optionally by "attachments" too).
=head1 LICENSE
Copyright [1999-2016] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
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.
=head1 CONTACT
Please subscribe to the Hive mailing list: http://listserver.ebi.ac.uk/mailman/listinfo/ehive-users to discuss Hive-related questions or to be notified of our updates
=cut
package Bio::EnsEMBL::Hive::RunnableDB::SlackNotification;
use strict;
use warnings;
use Bio::EnsEMBL::Hive::Utils::Slack ('send_message_to_slack');
use base ('Bio::EnsEMBL::Hive::Process');
sub param_defaults {
return {
# These parameters have a default value in the webhook, but can be overriden here
'channel' => undef,
'username' => undef,
'icon_url' => undef,
'icon_emoji' => undef, # wins if both icon_* parameters are defined
# If the sender wants something more fancy than a paragraph
'attachments' => undef,
};
}
sub run {
my $self = shift;
my $payload = {};
# required arguments
foreach my $k (qw(text)) {
$payload->{$k} = $self->param_required($k);
}
# optional arguments
foreach my $k (qw(username channel icon_emoji icon_url attachments)) {
$payload->{$k} = $self->param($k) if $self->param($k);
}
send_message_to_slack($self->param_required('slack_webhook'), $payload);
}
1;
=head1 LICENSE
Copyright [1999-2016] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
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.
=cut
=pod
=head1 NAME
Bio::EnsEMBL::Hive::Utils::Slack
=head1 DESCRIPTION
A library to interface eHive with Slack
=cut
package Bio::EnsEMBL::Hive::Utils::Slack;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT_OK = qw(send_message_to_slack send_beekeeper_message_to_slack);
=head2 send_message_to_slack
Description: A core method to send a message to a Slack webhook.
The payload should be a hash-structure that can be encoded in
JSON and follows Slack's message structure. See more details at
<https://api.slack.com/incoming-webhooks> and
<https://api.slack.com/docs/formatting>
=cut
sub send_message_to_slack {
my ($slack_webhook, $payload) = @_;
require HTTP::Request::Common;
require LWP::UserAgent;
require JSON;
# Fix the channel name (it *must* start with a hash)
$payload->{'channel'} = '#'.$payload->{'channel'} if ($payload->{'channel'} || '') =~ /^[^#]/;
my $req = HTTP::Request::Common::POST($slack_webhook, ['payload' => JSON::encode_json($payload)]);
my $ua = LWP::UserAgent->new;
$ua->timeout(15);
my $resp = $ua->request($req);
if ($resp->is_success) {
# well done
} else {
die $resp->status_line;
}
}
=head2 send_beekeeper_message_to_slack
Description: A method that is able to parse beekeeper's error messages and
make a Slack message. Note that this method *must* be in sync
with Queen
=cut
sub send_beekeeper_message_to_slack {
my ($slack_webhook, $hive_pipeline, $beekeeper_message) = @_;
my @attachments;
my $no_jobs_message = '### No jobs left to do ###';
my $has_failure = 0;
my $no_jobs_to_run = 0;
foreach my $reason (split /\n/, $beekeeper_message) {
if ($reason =~ /Analysis '(.*)' has FAILED \(failed Jobs: (\d+), tolerance: (.*)\%\)/) {
$has_failure = 1;
push @attachments, {
'color' => 'danger',
'fallback' => $reason,
'title' => "Analysis '$1' has failed",
'text' => "There are $2 failed jobs and the tolerance is $3%",
};
} elsif ($reason =~ /$no_jobs_message/) {
$no_jobs_to_run = 1;
}
}
if ($has_failure) {
push @attachments, {
'color' => 'warning',
'fallback' => $no_jobs_message,
'title' => 'beekeeper exited',
'mrkdwn_in' => [ 'text' ],
};
if ($no_jobs_to_run) {
$attachments[-1]->{'text'} = 'No jobs can be run (all _DONE_ or _FAILED_)';
} else {
$attachments[-1]->{'text'} = 'There are still some jobs to run, but some analyses are failing and `-keep_alive` has not been given';
}
} elsif ($no_jobs_to_run) {
push @attachments, {
'color' => 'good',
'fallback' => $no_jobs_message,
'title' => 'Pipeline completed',
};
} else {
# Not sure this case is possible
}
my $dbc = $hive_pipeline->hive_dba()->dbc();
my $payload = {
'text' => sprintf('Message from %s@%s:%s', $hive_pipeline->hive_pipeline_name, $dbc->host, $dbc->port),
'attachments' => \@attachments,
};
send_message_to_slack($slack_webhook, $payload);
}
1;
......@@ -15,6 +15,7 @@ BEGIN {
use Getopt::Long;
use File::Path 'make_path';
use Bio::EnsEMBL::Hive::Utils ('script_usage', 'destringify', 'report_versions');
use Bio::EnsEMBL::Hive::Utils::Slack ('send_beekeeper_message_to_slack');
use Bio::EnsEMBL::Hive::Utils::Config;
use Bio::EnsEMBL::Hive::HivePipeline;
use Bio::EnsEMBL::Hive::Queen;
......@@ -451,6 +452,9 @@ sub run_autonomously {
}
print "Beekeeper : stopped looping because ".( $reasons_to_exit || "the number of loops was limited by $max_loops and this limit expired\n");
if ($reasons_to_exit and $ENV{EHIVE_SLACK_WEBHOOK}) {
send_beekeeper_message_to_slack($ENV{EHIVE_SLACK_WEBHOOK}, $self->{'pipeline'}, $reasons_to_exit);
}
printf("Beekeeper: dbc %d disconnect cycles\n", $hive_dba->dbc->disconnect_count);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment