Converted PagerDuty to new transport format (#9092)

* Converted PagerDuty to new transport format

* Attempt at oauth for transports

* clean

* missing images

* reverted wrong file. phpstorm saved me...

* fix typo

* Updated to help the display

* Fix validation error, start to try to send alerts.
Editing the transport, deletes the service_key...

* Ignore hidden config options

* Fix up api call, proper feedback.

* hide oauth field in print list
This commit is contained in:
Neil Lathwood
2018-08-29 15:44:29 +01:00
committed by Tony Murray
parent b411f6c5d8
commit e603fcfd6f
9 changed files with 203 additions and 46 deletions

View File

@@ -23,25 +23,43 @@
*/
namespace LibreNMS\Alert\Transport;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use LibreNMS\Alert\Transport;
use Log;
use Validator;
class Pagerduty extends Transport
{
public static $integrationKey = '2fc7c9f3c8030e74aae6';
public function deliverAlert($obj, $opts)
{
if ($obj['state'] == 0) {
$obj['event_type'] = 'resolve';
} elseif ($obj['state'] == 2) {
$obj['event_type'] = 'acknowledge';
} else {
$obj['event_type'] = 'trigger';
}
if (empty($this->config)) {
return $this->deliverAlertEvent($obj, $opts);
}
return $this->contactPagerduty($obj, $this->config);
}
public function deliverAlertEvent($obj, $opts)
{
// This code uses events for PD
$protocol = array(
'service_key' => $opts,
'incident_key' => ($obj['id'] ? $obj['id'] : $obj['uid']),
'description' => ($obj['name'] ? $obj['name'] . ' on ' . $obj['hostname'] : $obj['title']),
'client' => 'LibreNMS',
);
if ($obj['state'] == 0) {
$protocol['event_type'] = 'resolve';
} elseif ($obj['state'] == 2) {
$protocol['event_type'] = 'acknowledge';
} else {
$protocol['event_type'] = 'trigger';
}
foreach ($obj['faults'] as $fault => $data) {
$protocol['details'][] = $data['string'];
}
@@ -60,13 +78,91 @@ class Pagerduty extends Transport
return true;
}
public function contactPagerduty()
/**
* @param $obj
* @param $config
* @return bool|string
*/
public function contactPagerduty($obj, $config)
{
return [];// Pagerduty is a custom transport.
$data = [
'routing_key' => $config['service_key'],
'event_action' => $obj['event_type'],
'dedup_key' => $obj['uid'],
'payload' => [
'summary' => implode(PHP_EOL, array_column($obj['faults'], 'string')) ?: 'Test',
'source' => $obj['hostname'],
'severity' => $obj['severity'],
],
];
$url = 'https://events.pagerduty.com/v2/enqueue';
$client = new Client();
try {
$result = $client->request('POST', $url, ['json' => $data]);
if ($result->getStatusCode() == 202) {
return true;
}
return $result->getReasonPhrase();
} catch (GuzzleException $e) {
return "Request to PagerDuty API failed. " . $e->getMessage();
}
}
public static function configTemplate()
{
return [];// Pagerduty is a custom transport.
return [
'config' => [
[
'title' => 'Authorize',
'descr' => 'Alert with PagerDuty',
'type' => 'oauth',
'icon' => 'pagerduty-white.svg',
'class' => 'btn-success',
'url' => 'https://connect.pagerduty.com/connect?vendor=' . self::$integrationKey . '&callback='
],
[
'title' => 'Account',
'type' => 'hidden',
'name' => 'account',
],
[
'title' => 'Service',
'type' => 'hidden',
'name' => 'service_name',
]
],
'validation' => []
];
}
public function handleOauth(Request $request)
{
$validator = Validator::make($request->all(), [
'account' => 'alpha_dash',
'service_key' => 'regex:/^[a-fA-F0-9]+$/',
'service_name' => 'string',
]);
if ($validator->fails()) {
Log::error('Pagerduty oauth failed validation.', ['request' => $request->all()]);
return false;
}
$config = json_encode($request->only('account', 'service_key', 'service_name'));
if ($id = $request->get('id')) {
return (bool)dbUpdate(['transport_config' => $config], 'alert_transports', 'transport_id=?', [$id]);
} else {
return (bool)dbInsert([
'transport_name' => $request->get('service_name', 'PagerDuty'),
'transport_type' => 'pagerduty',
'is_default' => 0,
'transport_config' => $config,
], 'alert_transports');
}
}
}

View File

@@ -254,9 +254,18 @@ LibreNMS can send alerts to osTicket API which are then converted to osTicket ti
| API Token | 123456789 |
## PagerDuty
PagerDuty setup is currently done by a two way integration. Start this process from Settings -> Alerting Settings from within LibreNMS.
LibreNMS can make use of PagerDuty, this is done by utilizing an API key and Integraton Key.
[PagerDuty Docs](https://www.pagerduty.com/docs/guides/librenms-integration-guide/)
API Keys can be found under 'API Access' in the PagerDuty portal.
Integration Keys can be found under 'Integration' for the particular Service you have created in the PagerDuty portal.
**Example:**
| Config | Example |
| ------ | ------- |
| API Key | randomsample |
| Integration Key | somerandomstring |
## Philips Hue
Want to spice up your noc life? LibreNMS will flash all lights connected to your philips hue bridge whenever an alert is triggered.

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 229.155 229.155"><g fill="#66ba68"><path d="M148.065 138.327c-.032 1.246.27 4.724 2.071 6.618 1.745 1.834 5.175 2.219 7.744 2.219h37.848c9.427-.129 9.427-7.21 9.427-9.54V82.059l-48.106-.019h-.054c-1.326 0-4.822.387-6.732 2.238-1.435 1.39-2.163 3.899-2.163 7.457zm47.626 32.837H157.88c-13.425 0-21.261-5.459-25.47-10.039-8.398-9.134-8.46-20.936-8.31-24.085V91.735c0-13.089 5.34-20.836 9.817-25.032 9.18-8.598 21.198-8.743 24.115-8.644h47.123V17.268h24v120.356c0 12.32-5.06 19.868-9.306 24.032-9.212 9.035-21.662 9.508-24.158 9.508M72.244 146.99c1.26-.016 4.873-.362 6.824-2.25 1.445-1.4 2.177-3.92 2.177-7.495l.034-46.699c.033-1.252-.27-4.75-2.084-6.656-1.755-1.845-5.2-2.233-7.781-2.233h-37.94C24 81.787 24 88.906 24 91.25v55.723zM24 211.887H0V91.249c0-12.34 5.067-19.9 9.318-24.069 9.412-9.232 22.163-9.545 24.335-9.523h37.76c13.446 0 21.294 5.467 25.51 10.054 8.41 9.149 8.472 20.97 8.322 24.122v45.412c0 13.109-5.347 20.868-9.831 25.07-9.191 8.608-21.219 8.756-24.153 8.657H24v40.915"/></g></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 229.155 229.155"><g fill="#fff"><path d="M148.065 138.327c-.032 1.246.27 4.724 2.071 6.618 1.745 1.834 5.175 2.219 7.744 2.219h37.848c9.427-.129 9.427-7.21 9.427-9.54V82.059l-48.106-.019h-.054c-1.326 0-4.822.387-6.732 2.238-1.435 1.39-2.163 3.899-2.163 7.457zm47.626 32.837H157.88c-13.425 0-21.261-5.459-25.47-10.039-8.398-9.134-8.46-20.936-8.31-24.085V91.735c0-13.089 5.34-20.836 9.817-25.032 9.18-8.598 21.198-8.743 24.115-8.644h47.123V17.268h24v120.356c0 12.32-5.06 19.868-9.306 24.032-9.212 9.035-21.662 9.508-24.158 9.508M72.244 146.99c1.26-.016 4.873-.362 6.824-2.25 1.445-1.4 2.177-3.92 2.177-7.495l.034-46.699c.033-1.252-.27-4.75-2.084-6.656-1.755-1.845-5.2-2.233-7.781-2.233h-37.94C24 81.787 24 88.906 24 91.25v55.723zM24 211.887H0V91.249c0-12.34 5.067-19.9 9.318-24.069 9.412-9.232 22.163-9.545 24.335-9.523h37.76c13.446 0 21.294 5.467 25.51 10.054 8.41 9.149 8.472 20.97 8.322 24.122v45.412c0 13.109-5.347 20.868-9.831 25.07-9.191 8.608-21.219 8.756-24.153 8.657H24v40.915"/></g></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -93,16 +93,19 @@ if (empty($name)) {
}
$status = 'error';
} else {
$transport_config = json_decode(dbFetchCell('SELECT transport_config FROM alert_transports WHERE transport_id=?', [$transport_id]), true);
foreach ($result['config'] as $tmp_config) {
$transport_config[$tmp_config['name']] = $vars[$tmp_config['name']];
if (isset($tmp_config['name']) && $tmp_config['type'] !== 'hidden') {
$transport_config[$tmp_config['name']] = $vars[$tmp_config['name']];
}
}
//Update the json config field
if ($transport_config) {
$transport_config = json_encode($transport_config);
$detail = array(
$detail = [
'transport_type' => $transport_type,
'transport_config' => $transport_config
);
];
$where = 'transport_id=?';
dbUpdate($detail, 'alert_transports', $where, [$transport_id]);

View File

@@ -56,6 +56,7 @@ if (Auth::user()->hasGlobalAdmin()) {
<option value="nagios-form">Nagios</option>
<option value="opsgenie-form">OpsGenie</option>
<option value="osticket-form">osTicket</option>
<option value="pagerduty-form">PagerDuty</option>
<option value="hue-form">Phillips Hue</option>
<option value="playsms-form">PlaySMS</option>
<option value="pushbullet-form">Pushbullet</option>
@@ -102,37 +103,51 @@ foreach (scandir($transport_dir) as $transport) {
$tmp = call_user_func($class.'::configTemplate');
foreach ($tmp['config'] as $item) {
echo '<div class="form-group" title="'.$item['descr'].'">';
echo '<label for="'.$item['name'].'" class="col-sm-3 col-md-2 control-label">'.$item['title'].': </label>';
if ($item['type'] == 'text') {
echo '<div class="col-sm-9 col-md-10">';
echo '<input type="'.$item['type'].'" id="'.$item['name'].'" name="'.$item['name'].'" class="form-control" ';
if ($item['required']) {
echo 'required>';
} else {
echo '>';
if ($item['type'] !== 'hidden') {
echo '<div class="form-group" title="' . $item['descr'] . '">';
echo '<label for="' . $item['name'] . '" class="col-sm-3 col-md-2 control-label">' . $item['title'] . ': </label>';
if ($item['type'] == 'text') {
echo '<div class="col-sm-9 col-md-10">';
echo '<input type="' . $item['type'] . '" id="' . $item['name'] . '" name="' . $item['name'] . '" class="form-control" ';
if ($item['required']) {
echo 'required>';
} else {
echo '>';
}
echo '</div>';
} elseif ($item['type'] == 'checkbox') {
echo '<div class="col-sm-2">';
echo '<input type="checkbox" name="' . $item['name'] . '" id="' . $item['name'] . '">';
echo '</div>';
$switches[$item['name']] = $item['default'];
} elseif ($item['type'] == 'select') {
echo '<div class="col-sm-3">';
echo '<select name="' . $item['name'] . '" id="' . $item['name'] . '" class="form-control">';
foreach ($item['options'] as $descr => $opt) {
echo '<option value="' . $opt . '">' . $descr . '</option>';
}
echo '</select>';
echo '</div>';
} elseif ($item['type'] === 'textarea') {
echo '<div class="col-sm-9 col-md-10">';
echo '<textarea name="' . $item['name'] . '" id="' . $item['name'] . '" class="form-control" placeholder="' . $item['descr'] . '">';
echo '</textarea>';
echo '</div>';
} elseif ($item['type'] === 'oauth') {
$class = isset($item['class']) ? $item['class'] : 'btn-success';
$callback = urlencode(url()->current() . '/?oauthtransport=' . $transport);
$url = $item['url'] . $callback;
echo '<a class="btn btn-oauth ' . $class . '"';
echo '" href="' . $url . '" data-base-url="' . $url . '">';
if (isset($item['icon'])) {
echo '<img src="' . asset('images/transports/' . $item['icon']) . '" width="24" height="24"> ';
}
echo $item['descr'];
echo '</a>';
}
echo '</div>';
} elseif ($item['type'] == 'checkbox') {
echo '<div class="col-sm-2">';
echo '<input type="checkbox" name="'.$item['name'].'" id="'.$item['name'].'">';
echo '</div>';
$switches[$item['name']] = $item['default'];
} elseif ($item['type'] == 'select') {
echo '<div class="col-sm-3">';
echo '<select name="'.$item['name'].'" id="'.$item['name'].'" class="form-control">';
foreach ($item['options'] as $descr => $opt) {
echo '<option value="'.$opt.'">'.$descr.'</option>';
}
echo '</select>';
echo '</div>';
} elseif ($item['type'] === 'textarea') {
echo '<div class="col-sm-9 col-md-10">';
echo '<textarea name="' . $item['name'] . '" id="' . $item['name'] . '" class="form-control" placeholder="'.$item['descr'].'">';
echo '</textarea>';
echo '</div>';
}
echo '</div>';
}
echo '<div class="form-group">';
echo '<div class="col-sm-12 text-center">';
@@ -236,6 +251,10 @@ foreach (scandir($transport_dir) as $transport) {
});
}
$(".btn-oauth").click(function (e) {
this.href = $(this).data('base-url') + '%26id=' + $("#transport_id").val();
});
// Save alert transport
$(".btn-save").on("click", function (e) {
e.preventDefault();

View File

@@ -60,6 +60,10 @@ foreach (dbFetchRows($query) as $transport) {
$transport_config = json_decode($transport['config'], true);
foreach ($tmp['config'] as $item) {
if ($item['type'] == 'oauth') {
continue;
}
$val = $transport_config[$item['name']];
// Match value to key name for select inputs

View File

@@ -1,3 +1,29 @@
<?php
// handle OAuth requests
$request = request(); // grab the Request object
if ($request->has('oauthtransport')) {
// make sure transport is safe
$validator = Validator::make($request->all(), ['oauthtransport' => 'required|alpha']);
if ($validator->passes()) {
$transport_name = $request->get('oauthtransport');
$class = 'LibreNMS\\Alert\\Transport\\'.$transport_name;
if (class_exists($class)) {
$transport = app($class);
if ($transport->handleOauth($request)) {
Toastr::success("$transport_name added successfully.");
} else {
Toastr::error("$transport_name was not added. Check the log for details.");
}
}
}
// remove get variables otherwise things will get double added
echo '<script>window.history.replaceState(null, null, window.location.pathname);</script>';
}
unset($request);
// print alert transports
require_once 'includes/print-alert-transports.php';

View File

@@ -606,9 +606,7 @@ function IssueAlert($alert)
$obj = DescribeAlert($alert);
if (is_array($obj)) {
echo 'Issuing Alert-UID #'.$alert['id'].'/'.$alert['state'].': ';
if (!empty($config['alert']['transports'])) {
ExtTransports($obj);
}
ExtTransports($obj);
echo "\r\n";
}