mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
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:
committed by
Tony Murray
parent
b411f6c5d8
commit
e603fcfd6f
@@ -23,25 +23,43 @@
|
|||||||
*/
|
*/
|
||||||
namespace LibreNMS\Alert\Transport;
|
namespace LibreNMS\Alert\Transport;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use LibreNMS\Alert\Transport;
|
use LibreNMS\Alert\Transport;
|
||||||
|
use Log;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
class Pagerduty extends Transport
|
class Pagerduty extends Transport
|
||||||
{
|
{
|
||||||
|
public static $integrationKey = '2fc7c9f3c8030e74aae6';
|
||||||
|
|
||||||
public function deliverAlert($obj, $opts)
|
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(
|
$protocol = array(
|
||||||
'service_key' => $opts,
|
'service_key' => $opts,
|
||||||
'incident_key' => ($obj['id'] ? $obj['id'] : $obj['uid']),
|
'incident_key' => ($obj['id'] ? $obj['id'] : $obj['uid']),
|
||||||
'description' => ($obj['name'] ? $obj['name'] . ' on ' . $obj['hostname'] : $obj['title']),
|
'description' => ($obj['name'] ? $obj['name'] . ' on ' . $obj['hostname'] : $obj['title']),
|
||||||
'client' => 'LibreNMS',
|
'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) {
|
foreach ($obj['faults'] as $fault => $data) {
|
||||||
$protocol['details'][] = $data['string'];
|
$protocol['details'][] = $data['string'];
|
||||||
}
|
}
|
||||||
@@ -60,13 +78,91 @@ class Pagerduty extends Transport
|
|||||||
return true;
|
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()
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -254,9 +254,18 @@ LibreNMS can send alerts to osTicket API which are then converted to osTicket ti
|
|||||||
| API Token | 123456789 |
|
| API Token | 123456789 |
|
||||||
|
|
||||||
## PagerDuty
|
## 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
|
## 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.
|
Want to spice up your noc life? LibreNMS will flash all lights connected to your philips hue bridge whenever an alert is triggered.
|
||||||
|
1
html/images/transports/pagerduty-green.svg
Normal file
1
html/images/transports/pagerduty-green.svg
Normal 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 |
1
html/images/transports/pagerduty-white.svg
Normal file
1
html/images/transports/pagerduty-white.svg
Normal 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 |
@@ -93,16 +93,19 @@ if (empty($name)) {
|
|||||||
}
|
}
|
||||||
$status = 'error';
|
$status = 'error';
|
||||||
} else {
|
} else {
|
||||||
|
$transport_config = json_decode(dbFetchCell('SELECT transport_config FROM alert_transports WHERE transport_id=?', [$transport_id]), true);
|
||||||
foreach ($result['config'] as $tmp_config) {
|
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
|
//Update the json config field
|
||||||
if ($transport_config) {
|
if ($transport_config) {
|
||||||
$transport_config = json_encode($transport_config);
|
$transport_config = json_encode($transport_config);
|
||||||
$detail = array(
|
$detail = [
|
||||||
'transport_type' => $transport_type,
|
'transport_type' => $transport_type,
|
||||||
'transport_config' => $transport_config
|
'transport_config' => $transport_config
|
||||||
);
|
];
|
||||||
$where = 'transport_id=?';
|
$where = 'transport_id=?';
|
||||||
|
|
||||||
dbUpdate($detail, 'alert_transports', $where, [$transport_id]);
|
dbUpdate($detail, 'alert_transports', $where, [$transport_id]);
|
||||||
|
@@ -56,6 +56,7 @@ if (Auth::user()->hasGlobalAdmin()) {
|
|||||||
<option value="nagios-form">Nagios</option>
|
<option value="nagios-form">Nagios</option>
|
||||||
<option value="opsgenie-form">OpsGenie</option>
|
<option value="opsgenie-form">OpsGenie</option>
|
||||||
<option value="osticket-form">osTicket</option>
|
<option value="osticket-form">osTicket</option>
|
||||||
|
<option value="pagerduty-form">PagerDuty</option>
|
||||||
<option value="hue-form">Phillips Hue</option>
|
<option value="hue-form">Phillips Hue</option>
|
||||||
<option value="playsms-form">PlaySMS</option>
|
<option value="playsms-form">PlaySMS</option>
|
||||||
<option value="pushbullet-form">Pushbullet</option>
|
<option value="pushbullet-form">Pushbullet</option>
|
||||||
@@ -102,37 +103,51 @@ foreach (scandir($transport_dir) as $transport) {
|
|||||||
$tmp = call_user_func($class.'::configTemplate');
|
$tmp = call_user_func($class.'::configTemplate');
|
||||||
|
|
||||||
foreach ($tmp['config'] as $item) {
|
foreach ($tmp['config'] as $item) {
|
||||||
echo '<div class="form-group" title="'.$item['descr'].'">';
|
if ($item['type'] !== 'hidden') {
|
||||||
echo '<label for="'.$item['name'].'" class="col-sm-3 col-md-2 control-label">'.$item['title'].': </label>';
|
echo '<div class="form-group" title="' . $item['descr'] . '">';
|
||||||
if ($item['type'] == 'text') {
|
echo '<label for="' . $item['name'] . '" class="col-sm-3 col-md-2 control-label">' . $item['title'] . ': </label>';
|
||||||
echo '<div class="col-sm-9 col-md-10">';
|
if ($item['type'] == 'text') {
|
||||||
echo '<input type="'.$item['type'].'" id="'.$item['name'].'" name="'.$item['name'].'" class="form-control" ';
|
echo '<div class="col-sm-9 col-md-10">';
|
||||||
if ($item['required']) {
|
echo '<input type="' . $item['type'] . '" id="' . $item['name'] . '" name="' . $item['name'] . '" class="form-control" ';
|
||||||
echo 'required>';
|
if ($item['required']) {
|
||||||
} else {
|
echo 'required>';
|
||||||
echo '>';
|
} 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>';
|
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="form-group">';
|
||||||
echo '<div class="col-sm-12 text-center">';
|
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
|
// Save alert transport
|
||||||
$(".btn-save").on("click", function (e) {
|
$(".btn-save").on("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@@ -60,6 +60,10 @@ foreach (dbFetchRows($query) as $transport) {
|
|||||||
$transport_config = json_decode($transport['config'], true);
|
$transport_config = json_decode($transport['config'], true);
|
||||||
|
|
||||||
foreach ($tmp['config'] as $item) {
|
foreach ($tmp['config'] as $item) {
|
||||||
|
if ($item['type'] == 'oauth') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$val = $transport_config[$item['name']];
|
$val = $transport_config[$item['name']];
|
||||||
|
|
||||||
// Match value to key name for select inputs
|
// Match value to key name for select inputs
|
||||||
|
@@ -1,3 +1,29 @@
|
|||||||
<?php
|
<?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';
|
require_once 'includes/print-alert-transports.php';
|
||||||
|
@@ -606,9 +606,7 @@ function IssueAlert($alert)
|
|||||||
$obj = DescribeAlert($alert);
|
$obj = DescribeAlert($alert);
|
||||||
if (is_array($obj)) {
|
if (is_array($obj)) {
|
||||||
echo 'Issuing Alert-UID #'.$alert['id'].'/'.$alert['state'].': ';
|
echo 'Issuing Alert-UID #'.$alert['id'].'/'.$alert['state'].': ';
|
||||||
if (!empty($config['alert']['transports'])) {
|
ExtTransports($obj);
|
||||||
ExtTransports($obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "\r\n";
|
echo "\r\n";
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user