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
This commit is contained in:
PipoCanaja
2019-07-04 17:55:29 +02:00
committed by Neil Lathwood
parent fce185b55c
commit 55f67f42fe
4 changed files with 85 additions and 51 deletions

View File

@@ -16,6 +16,7 @@
/**
* API Transport
* @author f0o <f0o@devilcode.org>
* @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' => [

View File

@@ -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 <br/> 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 <br/> key=0987654321abcdef <br/> 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 <br/> notify = 1 <br/> 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 <br/> sound_warning=siren <br/> 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 <br/> username=myname <br/> icon_url=http://someurl/image.gif <br/> 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 <br/> 0834567891 |
## Syslog

View File

@@ -85,7 +85,7 @@ foreach ($transports_list as $transport) {
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') {
if ($item['type'] == 'text' || $item['type'] == 'password') {
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']) {

View File

@@ -65,7 +65,9 @@ foreach (dbFetchRows($query) as $transport) {
}
$val = $transport_config[$item['name']];
if ($item['type'] == 'password') {
$val = '<b>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;</b>';
}
// Match value to key name for select inputs
if ($item['type'] == 'select') {
$val = array_search($val, $item['options']);