diff --git a/LibreNMS/Alert/Transport/Pagerduty.php b/LibreNMS/Alert/Transport/Pagerduty.php index 9cb59ea8b0..81c95fec4c 100644 --- a/LibreNMS/Alert/Transport/Pagerduty.php +++ b/LibreNMS/Alert/Transport/Pagerduty.php @@ -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'); + } } } diff --git a/doc/Alerting/Transports.md b/doc/Alerting/Transports.md index 5bdbb889cc..13a915d5d8 100644 --- a/doc/Alerting/Transports.md +++ b/doc/Alerting/Transports.md @@ -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. diff --git a/html/images/transports/pagerduty-green.svg b/html/images/transports/pagerduty-green.svg new file mode 100644 index 0000000000..06ce72135b --- /dev/null +++ b/html/images/transports/pagerduty-green.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/html/images/transports/pagerduty-white.svg b/html/images/transports/pagerduty-white.svg new file mode 100644 index 0000000000..d08355f8cf --- /dev/null +++ b/html/images/transports/pagerduty-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/html/includes/forms/alert-transports.inc.php b/html/includes/forms/alert-transports.inc.php index 61ef959a85..7f86e400f7 100644 --- a/html/includes/forms/alert-transports.inc.php +++ b/html/includes/forms/alert-transports.inc.php @@ -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]); diff --git a/html/includes/modal/edit_alert_transport.inc.php b/html/includes/modal/edit_alert_transport.inc.php index 8cf628ea1a..a36a6cb603 100644 --- a/html/includes/modal/edit_alert_transport.inc.php +++ b/html/includes/modal/edit_alert_transport.inc.php @@ -56,6 +56,7 @@ if (Auth::user()->hasGlobalAdmin()) { + @@ -102,37 +103,51 @@ foreach (scandir($transport_dir) as $transport) { $tmp = call_user_func($class.'::configTemplate'); foreach ($tmp['config'] as $item) { - echo '