From 55f67f42fec28262fd0c62d5d2392a44d8edefb2 Mon Sep 17 00:00:00 2001 From: PipoCanaja <38363551+PipoCanaja@users.noreply.github.com> Date: Thu, 4 Jul 2019 17:55:29 +0200 Subject: [PATCH] Refactor Api transport to use Guzzle (and new variables syntax) (#10070) * Allow new {{ $xxxx }} syntax * Properly handle urlencode on variable values without braking the URL, and uses Blades * Doc Doc typo * use Guzzle for HTTP requests * Add Basic auth support * Doc update * clean * Revert Blades, but keep the {{ $xxxx }} syntax * Revert Blades, but keep the {{ $xxxx }} syntax * Init Vars and comments * Notifications * api-options are not required * Update notifications.rss --- LibreNMS/Alert/Transport/Api.php | 85 ++++++++++++++----- doc/Alerting/Transports.md | 45 +++++----- .../html/modal/edit_alert_transport.inc.php | 2 +- includes/html/print-alert-transports.php | 4 +- 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/LibreNMS/Alert/Transport/Api.php b/LibreNMS/Alert/Transport/Api.php index 4fd2fdc502..f4eab854d5 100644 --- a/LibreNMS/Alert/Transport/Api.php +++ b/LibreNMS/Alert/Transport/Api.php @@ -16,6 +16,7 @@ /** * API Transport * @author f0o + * @author PipoCanaja (github.com/PipoCanaja) * @copyright 2014 f0o, LibreNMS * @license GPL * @package LibreNMS @@ -25,42 +26,62 @@ namespace LibreNMS\Alert\Transport; use LibreNMS\Alert\Transport; +use GuzzleHttp\Client; class Api extends Transport { public function deliverAlert($obj, $opts) { $url = $this->config['api-url']; + $options = $this->config['api-options']; $method = $this->config['api-method']; - return $this->contactAPI($obj, $url, $method); + $auth = [$this->config['api-auth-username'], $this->config['api-auth-password']]; + return $this->contactAPI($obj, $url, $options, $method, $auth); } - private function contactAPI($obj, $api, $method) + private function contactAPI($obj, $api, $options, $method, $auth) { + $request_opts = []; + $query = []; + $method = strtolower($method); - list($host, $api) = explode("?", $api, 2); - foreach ($obj as $k => $v) { - $api = str_replace("%" . $k, $method == "get" ? urlencode($v) : $v, $api); - } - // var_dump($api); //FIXME: propper debuging - $curl = curl_init(); - set_curl_proxy($curl); - curl_setopt($curl, CURLOPT_URL, ($method == "get" ? $host."?".$api : $host)); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method)); - if (json_decode($api) !== null) { - curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); - } - curl_setopt($curl, CURLOPT_POSTFIELDS, $api); - $ret = curl_exec($curl); - $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); - if ($code != 200) { - var_dump("API '$host' returned Error"); //FIXME: propper debuging - var_dump("Params: ".$api); //FIXME: propper debuging - var_dump("Return: ".$ret); //FIXME: propper debuging - return 'HTTP Status code '.$code; + $host = explode("?", $api, 2)[0]; //we don't use the parameter part, cause we build it out of options. + + //get each line of key-values and process the variables; + foreach (preg_split("/\\r\\n|\\r|\\n/", $options) as $current_line) { + list($u_key, $u_val) = explode('=', $current_line, 2); + + // Replace the values + foreach ($obj as $p_key => $p_val) { + $u_val = str_replace("{{ $" . $p_key . ' }}', $p_val, $u_val); + } + + //store the parameter in the array for HTTP query + $query[$u_key] = $u_val; } + $client = new \GuzzleHttp\Client(); + if (isset($auth) && !empty($auth[0])) { + $request_opts['auth'] = $auth; + } + if ($method == "get") { + $request_opts['query'] = $query; + $res = $client->request('GET', $host, $request_opts); + } else { //Method POST + $request_opts['form_params'] = $query; + $res = $client->request('POST', $host, $request_opts); + } + + $code = $res->getStatusCode(); + if ($code != 200) { + var_dump("API '$host' returned Error"); + var_dump("Params:"); + var_dump($query); + var_dump("Response headers:"); + var_dump($res->getHeaders()); + var_dump("Return: ".$res->getReasonPhrase()); + return 'HTTP Status code '.$code; + } return true; } @@ -83,6 +104,24 @@ class Api extends Transport 'name' => 'api-url', 'descr' => 'API URL', 'type' => 'text', + ], + [ + 'title' => 'Options', + 'name' => 'api-options', + 'descr' => 'Enter the options (format: option=value separated by new lines)', + 'type' => 'textarea', + ], + [ + 'title' => 'Auth Username', + 'name' => 'api-auth-username', + 'descr' => 'Auth Username', + 'type' => 'text', + ], + [ + 'title' => 'Auth Password', + 'name' => 'api-auth-password', + 'descr' => 'Auth Password', + 'type' => 'password', ] ], 'validation' => [ diff --git a/doc/Alerting/Transports.md b/doc/Alerting/Transports.md index feb03a0274..9fd5692518 100644 --- a/doc/Alerting/Transports.md +++ b/doc/Alerting/Transports.md @@ -60,31 +60,32 @@ entered as a new line. | Config | Example | | ------ | ------- | | Alertmanager URL | http://alertmanager.example.com | -| Alertmanager Options: | source=librenms | -| | customlabel=value | +| Alertmanager Options: | source=librenms
customlabel=value | ## API -API transports definitions are a bit more complex than the E-Mail configuration. +API transports definitions are a bit more complex than the E-Mail configuration. It +allows to reach any service provider using POST or GET URLs (Like SMS provider, etc). -The URL can have the same placeholders as defined in the [Template-Syntax](Templates.md#syntax). - -If the `Api Method` is `get`, all placeholders will be URL-Encoded. - -The API transport uses cURL to call the APIs, therefore you might need -to install `php curl` to make it work. +The API-Option field can have the same placeholders as defined in the +[Template-Syntax](Templates.md#syntax). __Note__: it is highly recommended to define your own -[Templates](Templates.md) when you want to use the API transport. The -default template might exceed URL-length for GET requests and -therefore cause all sorts of errors. +[Templates](Templates.md) when you want to use the API transport. +You have to be carefull with length (for HTTP GET requests) and +should adapt to the Service Provider limits. **Example:** +The exemple below will use the API named sms-api of my.example.com and send the title of the alert to the provided number using the provided service key. Refer to your service documentation to configure it properly. + | Config | Example | | ------ | ------- | -| API Method | get | -| API URL | http://my.example.com/api | +| API Method | get | +| API URL | http://my.example.com/sms-api +| API Options | rcpt=0123456789
key=0987654321abcdef
msg=(LNMS) {{ $title }} | +| API Username | myUsername | +| API Password | myPassword | ## Boxcar @@ -211,9 +212,7 @@ for details on acceptable values. | API URL | https://api.hipchat.com/v1/rooms/message?auth_token=109jawregoaihj | | Room ID | 7654321 | | From Name | LibreNMS | -| Options | color = red | -| | notify = 1 | -| | message_format = text | +| Options | color = red
notify = 1
message_format = text | At present the following options are supported: `color`, `notify` and `message_format`. @@ -430,9 +429,7 @@ Application and setup the transport. | ------ | ------- | | Api Key | APPLICATIONAPIKEYGOESHERE | | User Key | USERKEYGOESHERE | -| Pushover Options | sound_critical=falling | -| | sound_warning=siren | -| | sound_ok=magic | +| Pushover Options | sound_critical=falling
sound_warning=siren
sound_ok=magic | ## Rocket.chat @@ -448,10 +445,7 @@ required value is for url, without this then no call to Rocket.chat will be made | Config | Example | | ------ | ------- | | Webhook URL | https://rocket.url/api/v1/chat.postMessage | -| Rocket.chat Options | channel=#Alerting | -| | username=myname | -| | icon_url=http://someurl/image.gif | -| | icon_emoji=:smirk: | +| Rocket.chat Options | channel=#Alerting
username=myname
icon_url=http://someurl/image.gif
icon_emoji=:smirk: | ## Slack @@ -491,8 +485,7 @@ either local or international dialling format. | SMSEagle Host | ip.add.re.ss | | User | smseagle_user | | Password | smseagle_user_password | -| Mobiles | +3534567890 | -| | 0834567891 | +| Mobiles | +3534567890
0834567891 | ## Syslog diff --git a/includes/html/modal/edit_alert_transport.inc.php b/includes/html/modal/edit_alert_transport.inc.php index 39c6333d85..16b7355807 100644 --- a/includes/html/modal/edit_alert_transport.inc.php +++ b/includes/html/modal/edit_alert_transport.inc.php @@ -85,7 +85,7 @@ foreach ($transports_list as $transport) { if ($item['type'] !== 'hidden') { echo '
'; echo ''; - if ($item['type'] == 'text') { + if ($item['type'] == 'text' || $item['type'] == 'password') { echo '
'; echo '