![]()
'),
+ 'summary' => $alert_data['title'],
];
- $curl = curl_init();
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/json', 'Expect:']);
- curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
- if ($this->config['use-json'] === 'on' && $obj['uid'] !== '000') {
- curl_setopt($curl, CURLOPT_POSTFIELDS, $obj['msg']);
- }
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code != 200) {
- var_dump('Microsoft Teams returned Error, retry later');
- return false;
+ $client = Http::client();
+
+ // template will contain raw json
+ if ($this->config['use-json'] === 'on') {
+ $msg = $alert_data['uid'] === '000'
+ ? $this->messageCard() // use pre-made MessageCard for tests
+ : $alert_data['msg'];
+
+ $client->withBody($msg, 'application/json');
}
- return true;
+ $res = $client->post($this->config['msteam-url'], $data);
+
+ if ($res->successful()) {
+ return true;
+ }
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $data['text'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -70,7 +62,7 @@ class Msteams extends Transport
[
'title' => 'Use JSON?',
'name' => 'use-json',
- 'descr' => 'Compose MessageCard with JSON rather than Markdown',
+ 'descr' => 'Compose MessageCard with JSON rather than Markdown. Your template must be valid MessageCard JSON',
'type' => 'checkbox',
'default' => false,
],
@@ -80,4 +72,48 @@ class Msteams extends Transport
],
];
}
+
+ private function messageCard(): string
+ {
+ return '{
+ "@context": "https://schema.org/extensions",
+ "@type": "MessageCard",
+ "potentialAction": [
+ {
+ "@type": "OpenUri",
+ "name": "View MessageCard Reference",
+ "targets": [
+ {
+ "os": "default",
+ "uri": "https://learn.microsoft.com/en-us/outlook/actionable-messages/message-card-reference"
+ }
+ ]
+ },
+ {
+ "@type": "OpenUri",
+ "name": "View LibreNMS Website",
+ "targets": [
+ {
+ "os": "default",
+ "uri": "https://www.librenms.org/"
+ }
+ ]
+ }
+ ],
+ "sections": [
+ {
+ "facts": [
+ {
+ "name": "Next Action:",
+ "value": "Make your alert template emit valid MessageCard Json"
+ }
+ ],
+ "text": "You have successfully sent a pre-formatted MessageCard message to teams."
+ }
+ ],
+ "summary": "Test Successful",
+ "themeColor": "0072C6",
+ "title": "Test MessageCard"
+}';
+ }
}
diff --git a/LibreNMS/Alert/Transport/Nagios.php b/LibreNMS/Alert/Transport/Nagios.php
index 42e5b7f951..5993bb08b6 100644
--- a/LibreNMS/Alert/Transport/Nagios.php
+++ b/LibreNMS/Alert/Transport/Nagios.php
@@ -24,17 +24,11 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
class Nagios extends Transport
{
- public function deliverAlert($obj, $opts)
- {
- $opts = $this->config['nagios-fifo'];
-
- return $this->contactNagios($obj, $opts);
- }
-
- public static function contactNagios($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
/*
host_perfdata_file_template=
@@ -51,20 +45,25 @@ class Nagios extends Transport
$format = '';
$format .= "[HOSTPERFDATA]\t";
- $format .= strtotime($obj['timestamp']) . "\t";
- $format .= $obj['hostname'] . "\t";
- $format .= md5($obj['rule']) . "\t"; //FIXME: Better entity
- $format .= ($obj['state'] ? $obj['severity'] : 'ok') . "\t";
+ $format .= strtotime($alert_data['timestamp']) . "\t";
+ $format .= $alert_data['hostname'] . "\t";
+ $format .= md5($alert_data['rule']) . "\t"; //FIXME: Better entity
+ $format .= ($alert_data['state'] ? $alert_data['severity'] : 'ok') . "\t";
$format .= "0\t";
$format .= "0\t";
- $format .= str_replace("\n", '', nl2br($obj['msg'])) . "\t";
+ $format .= str_replace("\n", '', nl2br($alert_data['msg'])) . "\t";
$format .= 'NULL'; //FIXME: What's the HOSTPERFDATA equivalent for LibreNMS? Oo
$format .= "\n";
- return file_put_contents($opts, $format);
+ $fifo = $this->config['nagios-fifo'];
+ if (filetype($fifo) !== 'fifo') {
+ throw new AlertTransportDeliveryException($alert_data, 0, 'File is not a fifo file! Refused to write to it.');
+ }
+
+ return file_put_contents($fifo, $format);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Opsgenie.php b/LibreNMS/Alert/Transport/Opsgenie.php
index 618540f511..4646604095 100755
--- a/LibreNMS/Alert/Transport/Opsgenie.php
+++ b/LibreNMS/Alert/Transport/Opsgenie.php
@@ -24,45 +24,25 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Opsgenie extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if (! empty($this->config)) {
- $opts['url'] = $this->config['genie-url'];
+ $url = $this->config['genie-url'];
+
+ $res = Http::client()->post($url, $alert_data);
+
+ if ($res->successful()) {
+ return true;
}
- return $this->contactOpsgenie($obj, $opts);
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), '', $alert_data);
}
- public function contactOpsgenie($obj, $opts)
- {
- $url = $opts['url'];
-
- $curl = curl_init();
-
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
- curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($obj));
-
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
-
- if ($code != 200) {
- var_dump('Error when sending post request to OpsGenie. Response code: ' . $code . ' Response body: ' . $ret); //FIXME: proper debugging
-
- return false;
- }
-
- return true;
- }
-
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Osticket.php b/LibreNMS/Alert/Transport/Osticket.php
index 8dbbe0f782..7a99c8843c 100644
--- a/LibreNMS/Alert/Transport/Osticket.php
+++ b/LibreNMS/Alert/Transport/Osticket.php
@@ -14,29 +14,20 @@ namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
use LibreNMS\Config;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Osticket extends Transport
{
- protected $name = 'osTicket';
+ protected string $name = 'osTicket';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if (! empty($this->config)) {
- $opts['url'] = $this->config['os-url'];
- $opts['token'] = $this->config['os-token'];
- }
-
- return $this->contactOsticket($obj, $opts);
- }
-
- public function contactOsticket($obj, $opts)
- {
- $url = $opts['url'];
- $token = $opts['token'];
+ $url = $this->config['os-url'];
+ $token = $this->config['os-token'];
$email = '';
- foreach (parse_email(Config::get('email_from')) as $from => $from_name) {
+ foreach (\LibreNMS\Util\Mail::parseEmails(Config::get('email_from')) as $from => $from_name) {
$email = $from_name . ' <' . $from . '>';
break;
}
@@ -44,34 +35,24 @@ class Osticket extends Transport
$protocol = [
'name' => 'LibreNMS',
'email' => $email,
- 'subject' => ($obj['name'] ? $obj['name'] . ' on ' . $obj['hostname'] : $obj['title']),
- 'message' => strip_tags($obj['msg']),
+ 'subject' => ($alert_data['name'] ? $alert_data['name'] . ' on ' . $alert_data['hostname'] : $alert_data['title']),
+ 'message' => strip_tags($alert_data['msg']),
'ip' => $_SERVER['REMOTE_ADDR'],
'attachments' => [],
];
- $curl = curl_init();
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_HTTPHEADER, [
- 'Content-type' => 'application/json',
- 'Expect:',
- 'X-API-Key: ' . $token,
- ]);
- curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($protocol));
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code != 201) {
- var_dump('osTicket returned Error, retry later');
+ $res = Http::client()->withHeaders([
+ 'X-API-Key' => $token,
+ ])->post($url, $protocol);
- return false;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $protocol);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Pagerduty.php b/LibreNMS/Alert/Transport/Pagerduty.php
index 801448e234..d7263463c3 100644
--- a/LibreNMS/Alert/Transport/Pagerduty.php
+++ b/LibreNMS/Alert/Transport/Pagerduty.php
@@ -23,80 +23,55 @@
namespace LibreNMS\Alert\Transport;
-use GuzzleHttp\Client;
-use GuzzleHttp\Exception\GuzzleException;
use LibreNMS\Alert\Transport;
use LibreNMS\Enum\AlertState;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Pagerduty extends Transport
{
- protected $name = 'PagerDuty';
+ protected string $name = 'PagerDuty';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if ($obj['state'] == AlertState::RECOVERED) {
- $obj['event_type'] = 'resolve';
- } elseif ($obj['state'] == AlertState::ACKNOWLEDGED) {
- $obj['event_type'] = 'acknowledge';
- } else {
- $obj['event_type'] = 'trigger';
- }
+ $event_action = match ($alert_data['state']) {
+ AlertState::RECOVERED => 'resolve',
+ AlertState::ACKNOWLEDGED => 'acknowledge',
+ default => 'trigger'
+ };
- return $this->contactPagerduty($obj, $this->config);
- }
-
- /**
- * @param array $obj
- * @param array $config
- * @return bool|string
- */
- public function contactPagerduty($obj, $config)
- {
- $safe_message = strip_tags($obj['msg']) ?: 'Test';
- $custom_details = ['message' => array_filter(explode("\n", $safe_message), 'strlen')];
+ $safe_message = strip_tags($alert_data['msg']) ?: 'Test';
+ $message = array_filter(explode("\n", $safe_message), 'strlen');
$data = [
- 'routing_key' => $config['service_key'],
- 'event_action' => $obj['event_type'],
- 'dedup_key' => (string) $obj['alert_id'],
+ 'routing_key' => $this->config['service_key'],
+ 'event_action' => $event_action,
+ 'dedup_key' => (string) $alert_data['alert_id'],
'payload' => [
- 'custom_details' => $custom_details,
- 'group' => (string) \DeviceCache::get($obj['device_id'])->groups->pluck('name'),
- 'source' => $obj['hostname'],
- 'severity' => $obj['severity'],
- 'summary' => ($obj['name'] ? $obj['name'] . ' on ' . $obj['hostname'] : $obj['title']),
+ 'custom_details' => ['message' => $message],
+ 'group' => (string) \DeviceCache::get($alert_data['device_id'])->groups->pluck('name'),
+ 'source' => $alert_data['hostname'],
+ 'severity' => $alert_data['severity'],
+ 'summary' => ($alert_data['name'] ? $alert_data['name'] . ' on ' . $alert_data['hostname'] : $alert_data['title']),
],
];
// EU service region
- if ($config['region'] == 'EU') {
- $url = 'https://events.eu.pagerduty.com/v2/enqueue';
- } elseif ($config['region'] == 'US') {
- // US service region
- $url = 'https://events.pagerduty.com/v2/enqueue';
- } else {
- $url = $config['custom-url'];
+ $url = match ($this->config['region']) {
+ 'EU' => 'https://events.eu.pagerduty.com/v2/enqueue',
+ 'US' => 'https://events.pagerduty.com/v2/enqueue',
+ default => $this->config['custom-url'],
+ };
+
+ $res = Http::client()->post($url, $data);
+
+ if ($res->successful()) {
+ return true;
}
- $client = new Client();
-
- $request_opts = ['json' => $data];
- $request_opts['proxy'] = Proxy::forGuzzle();
-
- try {
- $result = $client->request('POST', $url, $request_opts);
-
- if ($result->getStatusCode() == 202) {
- return true;
- }
-
- return $result->getReasonPhrase();
- } catch (GuzzleException $e) {
- return 'Request to PagerDuty API failed. ' . $e->getMessage();
- }
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), implode(PHP_EOL, $message), $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Playsms.php b/LibreNMS/Alert/Transport/Playsms.php
index d4aa68ce2c..9330a12d00 100644
--- a/LibreNMS/Alert/Transport/Playsms.php
+++ b/LibreNMS/Alert/Transport/Playsms.php
@@ -24,48 +24,40 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Playsms extends Transport
{
- protected $name = 'playSMS';
+ protected string $name = 'playSMS';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $playsms_opts['url'] = $this->config['playsms-url'];
- $playsms_opts['user'] = $this->config['playsms-user'];
- $playsms_opts['token'] = $this->config['playsms-token'];
- $playsms_opts['from'] = $this->config['playsms-from'];
- $playsms_opts['to'] = preg_split('/([,\r\n]+)/', $this->config['playsms-mobiles']);
+ $to = preg_split('/([,\r\n]+)/', $this->config['playsms-mobiles']);
- return $this->contactPlaysms($obj, $playsms_opts);
- }
-
- public static function contactPlaysms($obj, $opts)
- {
- $data = ['u' => $opts['user'], 'h' => $opts['token'], 'to' => implode(',', $opts['to']), 'msg' => $obj['title']];
- if (! empty($opts['from'])) {
- $data['from'] = $opts['from'];
- }
- $url = $opts['url'] . '&op=pv&' . http_build_query($data);
- $curl = curl_init($url);
-
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
-
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code > 202) {
- var_dump($ret);
-
- return;
+ $url = str_replace('?app=ws', '', $this->config['playsms-url']); // remove old format
+ $data = [
+ 'app' => 'ws',
+ 'op' => 'pv',
+ 'u' => $this->config['playsms-user'],
+ 'h' => $this->config['playsms-token'],
+ 'to' => implode(',', $to),
+ 'msg' => $alert_data['title'],
+ ];
+ if (! empty($this->config['playsms-from'])) {
+ $data['from'] = $this->config['playsms-from'];
}
- return true;
+ $res = Http::client()->get($url, $data);
+
+ if ($res->successful()) {
+ return true;
+ }
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $data['msg'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Pushbullet.php b/LibreNMS/Alert/Transport/Pushbullet.php
index 8734ada282..720f9d64bd 100644
--- a/LibreNMS/Alert/Transport/Pushbullet.php
+++ b/LibreNMS/Alert/Transport/Pushbullet.php
@@ -24,49 +24,29 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Pushbullet extends Transport
{
- public function deliverAlert($obj, $opts)
- {
- if (! empty($this->config)) {
- $opts = $this->config['pushbullet-token'];
- }
-
- return $this->contactPushbullet($obj, $opts);
- }
-
- public function contactPushbullet($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
// Note: At this point it might be useful to iterate through $obj['contacts'] and send each of them a note ?
+ $url = 'https://api.pushbullet.com/v2/pushes';
+ $data = ['type' => 'note', 'title' => $alert_data['title'], 'body' => $alert_data['msg']];
- $data = ['type' => 'note', 'title' => $obj['title'], 'body' => $obj['msg']];
- $data = json_encode($data);
+ $res = Http::client()
+ ->withToken($this->config['pushbullet-token'])
+ ->post($url, $data);
- $curl = curl_init('https://api.pushbullet.com/v2/pushes');
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
- curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_HTTPHEADER, [
- 'Content-Type: application/json',
- 'Content-Length: ' . strlen($data),
- 'Authorization: Bearer ' . $opts,
- ]);
-
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code > 201) {
- var_dump($ret);
-
- return 'HTTP Status code ' . $code;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Pushover.php b/LibreNMS/Alert/Transport/Pushover.php
index 4e6f7868b3..a74cb4690e 100644
--- a/LibreNMS/Alert/Transport/Pushover.php
+++ b/LibreNMS/Alert/Transport/Pushover.php
@@ -39,68 +39,57 @@ namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
use LibreNMS\Enum\AlertState;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Pushover extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $pushover_opts = $this->config;
- $pushover_opts['options'] = $this->parseUserOptions($this->config['options']);
+ $options = $this->parseUserOptions($this->config['options']);
- return $this->contactPushover($obj, $pushover_opts);
- }
-
- public function contactPushover($obj, $api)
- {
+ $url = 'https://api.pushover.net/1/messages.json';
$data = [];
- $data['token'] = $api['appkey'];
- $data['user'] = $api['userkey'];
- switch ($obj['severity']) {
+ $data['token'] = $this->config['appkey'];
+ $data['user'] = $this->config['userkey'];
+ switch ($alert_data['severity']) {
case 'critical':
$data['priority'] = 1;
- if (! empty($api['options']['sound_critical'])) {
- $data['sound'] = $api['options']['sound_critical'];
+ if (! empty($options['sound_critical'])) {
+ $data['sound'] = $options['sound_critical'];
}
break;
case 'warning':
$data['priority'] = 1;
- if (! empty($api['options']['sound_warning'])) {
- $data['sound'] = $api['options']['sound_warning'];
+ if (! empty($options['sound_warning'])) {
+ $data['sound'] = $options['sound_warning'];
}
break;
}
- switch ($obj['state']) {
+ switch ($alert_data['state']) {
case AlertState::RECOVERED:
$data['priority'] = 0;
- if (! empty($api['options']['sound_ok'])) {
- $data['sound'] = $api['options']['sound_ok'];
+ if (! empty($options['sound_ok'])) {
+ $data['sound'] = $options['sound_ok'];
}
break;
}
- $data['title'] = $obj['title'];
- $data['message'] = $obj['msg'];
- if ($api['options']) {
- $data = array_merge($data, $api['options']);
- }
- $curl = curl_init();
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, 'https://api.pushover.net/1/messages.json');
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code != 200) {
- var_dump('Pushover returned error'); //FIXME: proper debugging
-
- return 'HTTP Status code ' . $code;
+ $data['title'] = $alert_data['title'];
+ $data['message'] = $alert_data['msg'];
+ if ($options) {
+ $data = array_merge($data, $options);
}
- return true;
+ $res = Http::client()->asForm()->post($url, $data);
+
+ if ($res->successful()) {
+ return true;
+ }
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $data['message'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Rocket.php b/LibreNMS/Alert/Transport/Rocket.php
index 8655bf17af..c356a01fa3 100644
--- a/LibreNMS/Alert/Transport/Rocket.php
+++ b/LibreNMS/Alert/Transport/Rocket.php
@@ -24,62 +24,43 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Rocket extends Transport
{
- protected $name = 'Rocket Chat';
+ protected string $name = 'Rocket Chat';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
$rocket_opts = $this->parseUserOptions($this->config['rocket-options']);
- $rocket_opts['url'] = $this->config['rocket-url'];
- return $this->contactRocket($obj, $rocket_opts);
- }
-
- public static function contactRocket($obj, $api)
- {
- $host = $api['url'];
- $curl = curl_init();
- $rocket_msg = strip_tags($obj['msg']);
- $color = self::getColorForState($obj['state']);
+ $rocket_msg = strip_tags($alert_data['msg']);
$data = [
'attachments' => [
0 => [
'fallback' => $rocket_msg,
- 'color' => $color,
- 'title' => $obj['title'],
+ 'color' => self::getColorForState($alert_data['state']),
+ 'title' => $alert_data['title'],
'text' => $rocket_msg,
],
],
- 'channel' => $api['channel'] ?? null,
- 'username' => $api['username'] ?? null,
- 'icon_url' => $api['icon_url'] ?? null,
- 'icon_emoji' => $api['icon_emoji'] ?? null,
+ 'channel' => $rocket_opts['channel'] ?? null,
+ 'username' => $rocket_opts['username'] ?? null,
+ 'icon_url' => $rocket_opts['icon_url'] ?? null,
+ 'icon_emoji' => $rocket_opts['icon_emoji'] ?? null,
];
- $alert_message = json_encode($data);
- curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $host);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_POST, true);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $alert_message);
- $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: ' . $alert_message); //FIXME: propper debuging
- var_dump('Return: ' . $ret); //FIXME: propper debuging
+ $res = Http::client()->post($this->config['rocket-url'], $data);
- return 'HTTP Status code ' . $code;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $rocket_msg, $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Sensu.php b/LibreNMS/Alert/Transport/Sensu.php
index c9ae45e531..27ce50f972 100644
--- a/LibreNMS/Alert/Transport/Sensu.php
+++ b/LibreNMS/Alert/Transport/Sensu.php
@@ -22,13 +22,12 @@
namespace LibreNMS\Alert\Transport;
-use GuzzleHttp\Client;
-use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use LibreNMS\Alert\Transport;
use LibreNMS\Config;
use LibreNMS\Enum\AlertState;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Sensu extends Transport
{
@@ -38,152 +37,120 @@ class Sensu extends Transport
public const CRITICAL = 2;
public const UNKNOWN = 3;
- private static $status = [
- 'ok' => Sensu::OK,
- 'warning' => Sensu::WARNING,
- 'critical' => Sensu::CRITICAL,
+ private static array $status = [
+ 'ok' => self::OK,
+ 'warning' => self::WARNING,
+ 'critical' => self::CRITICAL,
];
- private static $severity = [
- 'recovered' => AlertState::RECOVERED,
- 'alert' => AlertState::ACTIVE,
- 'acknowledged' => AlertState::ACKNOWLEDGED,
- 'worse' => AlertState::WORSE,
- 'better' => AlertState::BETTER,
- ];
-
- /**
- * @var Client
- */
- private static $client = null;
-
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $sensu_opts = [];
- $sensu_opts['url'] = $this->config['sensu-url'] ? $this->config['sensu-url'] : 'http://127.0.0.1:3031';
- $sensu_opts['namespace'] = $this->config['sensu-namespace'] ? $this->config['sensu-namespace'] : 'default';
- $sensu_opts['prefix'] = $this->config['sensu-prefix'];
$sensu_opts['source-key'] = $this->config['sensu-source-key'];
- Sensu::$client = new Client();
+ $url = $this->config['sensu-url'] ?: 'http://127.0.0.1:3031';
+ $client = Http::client();
- try {
- return $this->contactSensu($obj, $sensu_opts);
- } catch (GuzzleException $e) {
- return 'Sending event to Sensu failed: ' . $e->getMessage();
- }
- }
-
- public static function contactSensu($obj, $opts)
- {
// The Sensu agent should be running on the poller - events can be sent directly to the backend but this has not been tested, and likely needs mTLS.
// The agent API is documented at https://docs.sensu.io/sensu-go/latest/reference/agent/#create-monitoring-events-using-the-agent-api
- $request_options = ['proxy' => Proxy::forGuzzle()];
- if (Sensu::$client->request('GET', $opts['url'] . '/healthz', $request_options)->getStatusCode() !== 200) {
- return 'Sensu API is not responding';
+
+ $health_check = $client->get($url . '/healthz')->status();
+ if ($health_check !== 200) {
+ throw new AlertTransportDeliveryException($alert_data, $health_check, 'Sensu API is not responding');
}
- if ($obj['state'] !== AlertState::RECOVERED && $obj['state'] !== AlertState::ACKNOWLEDGED && $obj['alerted'] === 0) {
+ if ($alert_data['state'] !== AlertState::RECOVERED && $alert_data['state'] !== AlertState::ACKNOWLEDGED && $alert_data['alerted'] === 0) {
// If this is the first event, send a forced "ok" dated (rrd.step / 2) seconds ago to tell Sensu the last time the check was healthy
- $data = Sensu::generateData($obj, $opts, Sensu::OK, round(Config::get('rrd.step', 300) / 2));
+ $data = $this->generateData($alert_data, self::OK, (int) round(Config::get('rrd.step', 300) / 2));
Log::debug('Sensu transport sent last good event to socket: ', $data);
- $request_options['json'] = $data;
- $result = Sensu::$client->request('POST', $opts['url'] . '/events', $request_options);
- if ($result->getStatusCode() !== 202) {
- return $result->getReasonPhrase();
+ $result = $client->post($url . '/events', $data);
+ if ($result->status() !== 202) {
+ throw new AlertTransportDeliveryException($alert_data, $result->status(), $result->body(), json_encode($data), $this->config);
}
sleep(5);
}
- $data = Sensu::generateData($obj, $opts, Sensu::calculateStatus($obj['state'], $obj['severity']));
- Log::debug('Sensu transport sent event to socket: ', $data);
+ $data = $this->generateData($alert_data, $this->calculateStatus($alert_data['state'], $alert_data['severity']));
- $request_options['json'] = $data;
- $result = Sensu::$client->request('POST', $opts['url'] . '/events', $request_options);
- if ($result->getStatusCode() === 202) {
+ $result = $client->post($url . '/events', $data);
+
+ if ($result->successful()) {
return true;
}
- return $result->getReasonPhrase();
+ throw new AlertTransportDeliveryException($alert_data, $result->status(), $result->body(), json_encode($data), $sensu_opts);
}
- public static function generateData($obj, $opts, $status, $offset = 0)
+ private function generateData(array $alert_data, int $status, int $offset = 0): array
{
+ $namespace = $this->config['sensu-namespace'] ?: 'default';
+
return [
'check' => [
'metadata' => [
- 'name' => Sensu::checkName($opts['prefix'], $obj['name']),
- 'namespace' => $opts['namespace'],
- 'annotations' => Sensu::generateAnnotations($obj),
+ 'name' => $this->checkName($this->config['sensu-prefix'], $alert_data['name']),
+ 'namespace' => $namespace,
+ 'annotations' => $this->generateAnnotations($alert_data),
],
- 'command' => sprintf('LibreNMS: %s', $obj['builder']),
+ 'command' => sprintf('LibreNMS: %s', $alert_data['builder']),
'executed' => time() - $offset,
'interval' => Config::get('rrd.step', 300),
'issued' => time() - $offset,
- 'output' => $obj['msg'],
+ 'output' => $alert_data['msg'],
'status' => $status,
],
'entity' => [
'metadata' => [
- 'name' => Sensu::getEntityName($obj, $opts['source-key']),
- 'namespace' => $opts['namespace'],
+ 'name' => $this->getEntityName($alert_data),
+ 'namespace' => $namespace,
],
'system' => [
- 'hostname' => $obj['hostname'],
- 'os' => $obj['os'],
+ 'hostname' => $alert_data['hostname'],
+ 'os' => $alert_data['os'],
],
],
];
}
- public static function generateAnnotations($obj)
+ private function generateAnnotations(array $alert_data): array
{
return array_filter([
'generated-by' => 'LibreNMS',
- 'acknowledged' => $obj['state'] === AlertState::ACKNOWLEDGED ? 'true' : 'false',
- 'contact' => $obj['sysContact'],
- 'description' => $obj['sysDescr'],
- 'location' => $obj['location'],
- 'documentation' => $obj['proc'],
- 'librenms-notes' => $obj['notes'],
- 'librenms-device-id' => strval($obj['device_id']),
- 'librenms-rule-id' => strval($obj['rule_id']),
- 'librenms-status-reason' => $obj['status_reason'],
+ 'acknowledged' => $alert_data['state'] === AlertState::ACKNOWLEDGED ? 'true' : 'false',
+ 'contact' => $alert_data['sysContact'],
+ 'description' => $alert_data['sysDescr'],
+ 'location' => $alert_data['location'],
+ 'documentation' => $alert_data['proc'],
+ 'librenms-notes' => $alert_data['notes'],
+ 'librenms-device-id' => strval($alert_data['device_id']),
+ 'librenms-rule-id' => strval($alert_data['rule_id']),
+ 'librenms-status-reason' => $alert_data['status_reason'],
], function (?string $s): bool {
return (bool) strlen($s); // strlen returns 0 for null, false or '', but 1 for integer 0 - unlike empty()
});
}
- public static function calculateStatus($state, $severity)
+ private function calculateStatus(int $state, string $severity): int
{
// Sensu only has a single short (status) to indicate both severity and status, so we need to map LibreNMS' state and severity onto it
if ($state === AlertState::RECOVERED) {
// LibreNMS alert is resolved, send ok
- return Sensu::OK;
+ return self::OK;
}
- if (array_key_exists($severity, Sensu::$status)) {
- // Severity is known, map the LibreNMS severity to the Sensu status
- return Sensu::$status[$severity];
- }
-
- // LibreNMS severity does not map to Sensu, send unknown
- return Sensu::UNKNOWN;
+ return self::$status[$severity] ?? self::UNKNOWN;
}
- public static function getEntityName($obj, $key)
+ private function getEntityName(array $obj): string
{
- if ($key === 'shortname') {
- return Sensu::shortenName($obj['display']);
- }
+ $key = $this->config['sensu-source-key'] ?: 'display';
- return $obj[$key];
+ return $key === 'shortname' ? $this->shortenName($obj['display']) : $obj[$key];
}
- public static function shortenName($name)
+ private function shortenName(string $name): string
{
// Shrink the last domain components - e.g. librenms.corp.example.net becomes librenms.cen
$components = explode('.', $name);
@@ -204,7 +171,7 @@ class Sensu extends Transport
return sprintf('%s.%s', implode('.', $components), $result);
}
- public static function checkName($prefix, $name)
+ private function checkName(string $prefix, string $name): string
{
$check = strtolower(str_replace(' ', '-', $name));
@@ -215,7 +182,7 @@ class Sensu extends Transport
return $check;
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Signal.php b/LibreNMS/Alert/Transport/Signal.php
index f833a1671c..387b963f9c 100644
--- a/LibreNMS/Alert/Transport/Signal.php
+++ b/LibreNMS/Alert/Transport/Signal.php
@@ -26,29 +26,18 @@ use LibreNMS\Alert\Transport;
class Signal extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $signalOpts = [
- 'path' => escapeshellarg($this->config['path']),
- 'recipient-type' => ($this->config['recipient-type'] == 'group') ? ' -g ' : ' ',
- 'recipient' => escapeshellarg($this->config['recipient']),
- ];
-
- return $this->contactSignal($obj, $signalOpts);
- }
-
- public function contactSignal($obj, $opts)
- {
- exec($opts['path']
+ exec(escapeshellarg($this->config['path'])
. ' --dbus-system send'
- . $opts['recipient-type']
- . $opts['recipient']
- . ' -m ' . escapeshellarg($obj['title']));
+ . (($this->config['recipient-type'] == 'group') ? ' -g ' : ' ')
+ . escapeshellarg($this->config['recipient'])
+ . ' -m ' . escapeshellarg($alert_data['title']));
return true;
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'validation' => [],
diff --git a/LibreNMS/Alert/Transport/Signalwire.php b/LibreNMS/Alert/Transport/Signalwire.php
index d1c751b54b..bac12103f8 100644
--- a/LibreNMS/Alert/Transport/Signalwire.php
+++ b/LibreNMS/Alert/Transport/Signalwire.php
@@ -18,62 +18,35 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Signalwire extends Transport
{
- protected $name = 'SignalWire';
+ protected string $name = 'SignalWire';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $signalwire_opts['spaceUrl'] = $this->config['signalwire-spaceUrl'];
- $signalwire_opts['sid'] = $this->config['signalwire-project-id'];
- $signalwire_opts['token'] = $this->config['signalwire-token'];
- $signalwire_opts['sender'] = $this->config['signalwire-sender'];
- $signalwire_opts['to'] = $this->config['signalwire-to'];
-
- return $this->contactSignalwire($obj, $signalwire_opts);
- }
-
- public static function contactSignalwire($obj, $opts)
- {
- $params = [
- 'spaceUrl' => $opts['spaceUrl'],
- 'sid' => $opts['sid'],
- 'token' => $opts['token'],
- 'phone' => $opts['to'],
- 'text' => $obj['title'],
- 'sender' => $opts['sender'],
- ];
-
- $url = 'https://' . $params['spaceUrl'] . '.signalwire.com/api/laml/2010-04-01/Accounts/' . $params['sid'] . '/Messages.json';
+ $url = 'https://' . $this->config['signalwire-spaceUrl'] . '.signalwire.com/api/laml/2010-04-01/Accounts/' . $this->config['signalwire-project-id'] . '/Messages.json';
$data = [
- 'From' => $params['sender'],
- 'Body' => $params['text'],
- 'To' => $params['phone'],
+ 'From' => $this->config['signalwire-sender'],
+ 'To' => $this->config['signalwire-to'],
+ 'Body' => $alert_data['title'],
];
- $post = http_build_query($data);
- $curl = curl_init($url);
+ $res = Http::client()->asForm()
+ ->withBasicAuth($this->config['signalwire-project-id'], $this->config['signalwire-token'])
+ ->post($url, $data);
- Proxy::applyToCurl($curl);
-
- curl_setopt($curl, CURLOPT_POST, true);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_setopt($curl, CURLOPT_USERPWD, $params['sid'] . ':' . $params['token']);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
-
- curl_exec($curl);
-
- if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE)) {
+ if ($res->successful()) {
return true;
}
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['title'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Slack.php b/LibreNMS/Alert/Transport/Slack.php
index fa96749453..063a115d82 100644
--- a/LibreNMS/Alert/Transport/Slack.php
+++ b/LibreNMS/Alert/Transport/Slack.php
@@ -23,62 +23,44 @@
namespace LibreNMS\Alert\Transport;
+use Illuminate\Support\Str;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Slack extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $slack_opts = $this->parseUserOptions($this->config['slack-options']);
- $slack_opts['url'] = $this->config['slack-url'];
+ $slack_opts = $this->parseUserOptions($this->config['slack-options'] ?? '');
+ $icon = $this->config['slack-icon_emoji'] ?? $slack_opts['icon_emoji'] ?? null;
+ $slack_msg = html_entity_decode(strip_tags($alert_data['msg'] ?? ''), ENT_QUOTES);
- return $this->contactSlack($obj, $slack_opts);
- }
-
- public static function contactSlack($obj, $api)
- {
- $host = $api['url'];
- $curl = curl_init();
- $slack_msg = html_entity_decode(strip_tags($obj['msg'] ?? ''), ENT_QUOTES);
- $color = self::getColorForState($obj['state']);
$data = [
'attachments' => [
0 => [
'fallback' => $slack_msg,
- 'color' => $color,
- 'title' => $obj['title'] ?? null,
+ 'color' => self::getColorForState($alert_data['state']),
+ 'title' => $alert_data['title'] ?? null,
'text' => $slack_msg,
'mrkdwn_in' => ['text', 'fallback'],
- 'author_name' => $api['author_name'] ?? null,
+ 'author_name' => $this->config['slack-author'] ?? $slack_opts['author'] ?? null,
],
],
- 'channel' => $api['channel'] ?? null,
- 'username' => $api['username'] ?? null,
- 'icon_emoji' => isset($api['icon_emoji']) ? ':' . $api['icon_emoji'] . ':' : null,
+ 'channel' => $this->config['slack-channel'] ?? $slack_opts['channel'] ?? null,
+ 'icon_emoji' => $icon ? Str::finish(Str::start($icon, ':'), ':') : null,
];
- $alert_message = json_encode($data);
- curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $host);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_POST, true);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $alert_message);
- $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: ' . $alert_message); //FIXME: propper debuging
- var_dump('Return: ' . $ret); //FIXME: propper debuging
+ $res = Http::client()->post($this->config['slack-url'] ?? '', $data);
- return 'HTTP Status code ' . $code;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $slack_msg, $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -89,14 +71,30 @@ class Slack extends Transport
'type' => 'text',
],
[
- 'title' => 'Slack Options',
- 'name' => 'slack-options',
- 'descr' => 'Slack Options',
- 'type' => 'textarea',
+ 'title' => 'Channel',
+ 'name' => 'slack-channel',
+ 'descr' => 'Channel to post to',
+ 'type' => 'text',
+ ],
+ [
+ 'title' => 'Author Name',
+ 'name' => 'slack-author',
+ 'descr' => 'Name of author',
+ 'type' => 'text',
+ 'default' => 'LibreNMS',
+ ],
+ [
+ 'title' => 'Icon',
+ 'name' => 'slack-author',
+ 'descr' => 'Name of emoji for icon',
+ 'type' => 'text',
],
],
'validation' => [
'slack-url' => 'required|url',
+ 'slack-channel' => 'string',
+ 'slack-username' => 'string',
+ 'slack-icon_emoji' => 'string',
],
];
}
diff --git a/LibreNMS/Alert/Transport/Smseagle.php b/LibreNMS/Alert/Transport/Smseagle.php
index 43cf047658..f5c2504383 100644
--- a/LibreNMS/Alert/Transport/Smseagle.php
+++ b/LibreNMS/Alert/Transport/Smseagle.php
@@ -23,49 +23,44 @@
namespace LibreNMS\Alert\Transport;
-use Illuminate\Support\Str;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Smseagle extends Transport
{
- protected $name = 'SMSEagle';
+ protected string $name = 'SMSEagle';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $smseagle_opts['url'] = $this->config['smseagle-url'];
- $smseagle_opts['user'] = $this->config['smseagle-user'];
- $smseagle_opts['token'] = $this->config['smseagle-pass'];
- $smseagle_opts['to'] = preg_split('/([,\r\n]+)/', $this->config['smseagle-mobiles']);
-
- return $this->contactSmseagle($obj, $smseagle_opts);
- }
-
- public static function contactSmseagle($obj, $opts)
- {
- $params = [
- 'login' => $opts['user'],
- 'pass' => $opts['token'],
- 'to' => implode(',', $opts['to']),
- 'message' => $obj['title'],
- ];
- $url = Str::startsWith($opts['url'], 'http') ? '' : 'http://';
- $url .= $opts['url'] . '/index.php/http_api/send_sms?' . http_build_query($params);
- $curl = curl_init($url);
-
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
-
- $ret = curl_exec($curl);
- if (substr($ret, 0, 2) == 'OK') {
- return true;
- } else {
- return false;
+ $url = $this->config['smseagle-url'] . '/http_api/send_sms';
+ if (! str_starts_with($url, 'http')) {
+ $url = 'http://' . $url;
}
+
+ $params = [];
+
+ // use token if available
+ if (empty($this->config['smseagle-token'])) {
+ $params['login'] = $this->config['smseagle-user'];
+ $params['pass'] = $this->config['smseagle-pass'];
+ } else {
+ $params['access_token'] = $this->config['smseagle-token'];
+ }
+
+ $params['to'] = implode(',', preg_split('/([,\r\n]+)/', $this->config['smseagle-mobiles']));
+ $params['message'] = $alert_data['title'];
+
+ $res = Http::client()->get($url, $params);
+
+ if ($res->successful() && str_starts_with($res->body(), 'OK')) {
+ return true;
+ }
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $params['message'], $params);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -75,6 +70,12 @@ class Smseagle extends Transport
'descr' => 'SMSEagle Host',
'type' => 'text',
],
+ [
+ 'title' => 'Access Token',
+ 'name' => 'smseagle-token',
+ 'descr' => 'SMSEagle Access Token',
+ 'type' => 'text',
+ ],
[
'title' => 'User',
'name' => 'smseagle-user',
@@ -96,8 +97,9 @@ class Smseagle extends Transport
],
'validation' => [
'smseagle-url' => 'required|url',
- 'smseagle-user' => 'required|string',
- 'smseagle-pass' => 'required|string',
+ 'smseagle-token' => 'required_without:smseagle-user,smseagle-pass|string',
+ 'smseagle-user' => 'required_without:smseagle-token|string',
+ 'smseagle-pass' => 'required_without:smseagle-token|string',
'smseagle-mobiles' => 'required',
],
];
diff --git a/LibreNMS/Alert/Transport/Smsfeedback.php b/LibreNMS/Alert/Transport/Smsfeedback.php
index dbdeb163dc..6e9378d7d4 100644
--- a/LibreNMS/Alert/Transport/Smsfeedback.php
+++ b/LibreNMS/Alert/Transport/Smsfeedback.php
@@ -24,45 +24,34 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Smsfeedback extends Transport
{
- protected $name = 'SMSfeedback';
+ protected string $name = 'SMSfeedback';
- public function deliverAlert($obj, $opts)
- {
- $smsfeedback_opts['user'] = $this->config['smsfeedback-user'];
- $smsfeedback_opts['token'] = $this->config['smsfeedback-pass'];
- $smsfeedback_opts['sender'] = $this->config['smsfeedback-sender'];
- $smsfeedback_opts['to'] = $this->config['smsfeedback-mobiles'];
-
- return $this->contactsmsfeedback($obj, $smsfeedback_opts);
- }
-
- public static function contactsmsfeedback($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
+ $url = 'http://api.smsfeedback.ru/messages/v2/send/';
$params = [
- 'login' => $opts['user'],
- 'pass' => md5($opts['token']),
- 'phone' => $opts['to'],
- 'text' => $obj['title'],
- 'sender' => $opts['sender'],
+ 'phone' => $this->config['smsfeedback-mobiles'],
+ 'text' => $alert_data['title'],
+ 'sender' => $this->config['smsfeedback-sender'],
];
- $url = 'http://' . $opts['user'] . ':' . $opts['token'] . '@' . 'api.smsfeedback.ru/messages/v2/send/?' . http_build_query($params);
- $curl = curl_init($url);
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $res = Http::client()
+ ->withBasicAuth($this->config['smsfeedback-user'], $this->config['smsfeedback-pass'])
+ ->get($url, $params);
- $ret = curl_exec($curl);
- if (substr($ret, 0, 8) == 'accepted') {
+ if ($res->successful() && str_starts_with($res->body(), 'accepted')) {
return true;
}
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['title'], $params);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -95,7 +84,7 @@ class Smsfeedback extends Transport
'smsfeedback-user' => 'required|string',
'smsfeedback-pass' => 'required|string',
'smsfeedback-mobiles' => 'required',
- 'smsfeedback-sender' => 'required|string',
+ 'smsfeedback-sender' => 'required|string',
],
];
}
diff --git a/LibreNMS/Alert/Transport/Splunk.php b/LibreNMS/Alert/Transport/Splunk.php
index a079024857..96ee7d3e2f 100644
--- a/LibreNMS/Alert/Transport/Splunk.php
+++ b/LibreNMS/Alert/Transport/Splunk.php
@@ -19,51 +19,18 @@ namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
use LibreNMS\Enum\AlertState;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
class Splunk extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if (! empty($this->config)) {
- $opts['splunk_host'] = $this->config['Splunk-host'];
- $opts['splunk_port'] = $this->config['Splunk-port'];
- }
-
- return $this->contactSplunk($obj, $opts);
- }
-
- public function contactSplunk($obj, $opts)
- {
- $splunk_host = '127.0.0.1';
- $splunk_port = 514;
+ $splunk_host = empty($this->config['Splunk-host']) ? '127.0.0.1' : $this->config['Splunk-host'];
+ $splunk_port = empty($this->config['Splunk-port']) ? 514 : $this->config['Splunk-port'];
$severity = 6; // Default severity is 6 (Informational)
- $device = device_by_id_cache($obj['device_id']); // for event logging
+ $device = device_by_id_cache($alert_data['device_id']); // for event logging
- if (! empty($opts['splunk_host'])) {
- if (preg_match('/[a-zA-Z]/', $opts['splunk_host'])) {
- $splunk_host = gethostbyname($opts['splunk_host']);
- if ($splunk_host === $opts['splunk_host']) {
- log_event('Alphanumeric hostname found but does not resolve to an IP.', $device, 'poller', 5);
-
- return false;
- }
- } elseif (filter_var($opts['splunk_host'], FILTER_VALIDATE_IP)) {
- $splunk_host = $opts['splunk_host'];
- } else {
- log_event('Splunk host is not a valid IP: ' . $opts['splunk_host'], $device, 'poller', 5);
-
- return false;
- }
- } else {
- log_event('Splunk host is empty.', $device, 'poller');
- }
- if (! empty($opts['splunk_port']) && preg_match("/^\d+$/", $opts['splunk_port'])) {
- $splunk_port = $opts['splunk_port'];
- } else {
- log_event('Splunk port is not an integer.', $device, 'poller', 5);
- }
-
- switch ($obj['severity']) {
+ switch ($alert_data['severity']) {
case 'critical':
$severity = 2;
break;
@@ -72,7 +39,7 @@ class Splunk extends Transport
break;
}
- switch ($obj['state']) {
+ switch ($alert_data['state']) {
case AlertState::RECOVERED:
$severity = 6;
break;
@@ -83,7 +50,7 @@ class Splunk extends Transport
$ignore = ['template', 'contacts', 'rule', 'string', 'debug', 'faults', 'builder', 'transport', 'alert', 'msg', 'transport_name'];
$splunk_prefix = '<' . $severity . '> ';
- foreach ($obj as $key => $val) {
+ foreach ($alert_data as $key => $val) {
if (in_array($key, $ignore)) {
continue;
}
@@ -102,26 +69,24 @@ class Splunk extends Transport
$splunk_prefix = substr($splunk_prefix, 0, -1);
if (($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) === false) {
- log_event('socket_create() failed: reason: ' . socket_strerror(socket_last_error()), $device, 'poller', 5);
+ throw new AlertTransportDeliveryException($alert_data, 0, 'socket_create() failed: reason: ' . socket_strerror(socket_last_error()));
+ }
- return false;
- } else {
- if (! empty($obj['faults'])) {
- foreach ($obj['faults'] as $k => $v) {
- $splunk_msg = $splunk_prefix . ' - ' . $v['string'];
- socket_sendto($socket, $splunk_msg, strlen($splunk_msg), 0, $splunk_host, $splunk_port);
- }
- } else {
- $splunk_msg = $splunk_prefix;
+ if (! empty($alert_data['faults'])) {
+ foreach ($alert_data['faults'] as $fault) {
+ $splunk_msg = $splunk_prefix . ' - ' . $fault['string'];
socket_sendto($socket, $splunk_msg, strlen($splunk_msg), 0, $splunk_host, $splunk_port);
}
- socket_close($socket);
+ } else {
+ $splunk_msg = $splunk_prefix;
+ socket_sendto($socket, $splunk_msg, strlen($splunk_msg), 0, $splunk_host, $splunk_port);
}
+ socket_close($socket);
return true;
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -130,17 +95,19 @@ class Splunk extends Transport
'name' => 'Splunk-host',
'descr' => 'Splunk Host',
'type' => 'text',
+ 'default' => '127.0.0.1',
],
[
'title' => 'UDP Port',
'name' => 'Splunk-port',
'descr' => 'Splunk Port',
'type' => 'text',
+ 'default' => 514,
],
],
'validation' => [
- 'Splunk-host' => 'required|string',
- 'Splunk-port' => 'required|numeric',
+ 'Splunk-host' => 'required|ip_or_hostname',
+ 'Splunk-port' => 'integer|between:1,65536',
],
];
}
diff --git a/LibreNMS/Alert/Transport/Syslog.php b/LibreNMS/Alert/Transport/Syslog.php
index a666814039..0170eacd85 100644
--- a/LibreNMS/Alert/Transport/Syslog.php
+++ b/LibreNMS/Alert/Transport/Syslog.php
@@ -19,21 +19,16 @@ namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
use LibreNMS\Enum\AlertState;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
class Syslog extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if (! empty($this->config)) {
- $opts['syslog_host'] = $this->config['syslog-host'];
- $opts['syslog_port'] = $this->config['syslog-port'];
- $opts['syslog_facility'] = $this->config['syslog-facility'];
- }
-
- return $this->contactSyslog($obj, $opts);
+ return $this->contactSyslog($alert_data);
}
- public function contactSyslog($obj, $opts)
+ public function contactSyslog(array $alert_data): bool
{
$syslog_host = '127.0.0.1';
$syslog_port = 514;
@@ -41,38 +36,26 @@ class Syslog extends Transport
$facility = 24; // Default facility is 3 * 8 (daemon)
$severity = 6; // Default severity is 6 (Informational)
$sev_txt = 'OK';
- $device = device_by_id_cache($obj['device_id']); // for event logging
- if (! empty($opts['syslog_facility']) && preg_match("/^\d+$/", $opts['syslog_facility'])) {
- $facility = (int) $opts['syslog_facility'] * 8;
- } else {
- log_event('Syslog facility is not an integer: ' . $opts['syslog_facility'], $device, 'poller', 5);
+ if (! empty($this->config['syslog-facility'])) {
+ $facility = (int) $this->config['syslog-facility'] * 8;
}
- if (! empty($opts['syslog_host'])) {
- if (preg_match('/[a-zA-Z]/', $opts['syslog_host'])) {
- $syslog_host = gethostbyname($opts['syslog_host']);
- if ($syslog_host === $opts['syslog_host']) {
- log_event('Alphanumeric hostname found but does not resolve to an IP.', $device, 'poller', 5);
- return false;
+ if (! empty($this->config['syslog-host'])) {
+ if (preg_match('/[a-zA-Z]/', $this->config['syslog-host'])) {
+ $syslog_host = gethostbyname($this->config['syslog-host']);
+ if ($syslog_host === $this->config['syslog-host']) {
+ throw new AlertTransportDeliveryException($alert_data, 0, 'Hostname found but does not resolve to an IP.');
}
- } elseif (filter_var($opts['syslog_host'], FILTER_VALIDATE_IP)) {
- $syslog_host = $opts['syslog_host'];
- } else {
- log_event('Syslog host is not a valid IP: ' . $opts['syslog_host'], $device, 'poller', 5);
-
- return false;
}
- } else {
- log_event('Syslog host is empty.', $device, 'poller');
- }
- if (! empty($opts['syslog_port']) && preg_match("/^\d+$/", $opts['syslog_port'])) {
- $syslog_port = $opts['syslog_port'];
- } else {
- log_event('Syslog port is not an integer.', $device, 'poller', 5);
+ $syslog_host = $this->config['syslog-host'];
}
- switch ($obj['severity']) {
+ if (! empty($this->config['syslog-port'])) {
+ $syslog_port = $this->config['syslog-port'];
+ }
+
+ switch ($alert_data['severity']) {
case 'critical':
$severity = 2;
$sev_txt = 'Critical';
@@ -83,7 +66,7 @@ class Syslog extends Transport
break;
}
- switch ($obj['state']) {
+ switch ($alert_data['state']) {
case AlertState::RECOVERED:
$state = 'OK';
$severity = 6;
@@ -106,35 +89,33 @@ class Syslog extends Transport
. gethostname()
. ' librenms'
. '['
- . $obj['device_id']
+ . $alert_data['device_id']
. ']: '
- . $obj['hostname']
+ . $alert_data['hostname']
. ': ['
. $state
. '] '
- . $obj['name'];
+ . $alert_data['name'];
if (($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) === false) {
- log_event('socket_create() failed: reason: ' . socket_strerror(socket_last_error()), $device, 'poller', 5);
+ throw new AlertTransportDeliveryException($alert_data, 0, 'socket_create() failed: reason: ' . socket_strerror(socket_last_error()));
+ }
- return false;
- } else {
- if (! empty($obj['faults'])) {
- foreach ($obj['faults'] as $k => $v) {
- $syslog_msg = $syslog_prefix . ' - ' . $v['string'];
- socket_sendto($socket, $syslog_msg, strlen($syslog_msg), 0, $syslog_host, $syslog_port);
- }
- } else {
- $syslog_msg = $syslog_prefix;
+ if (! empty($alert_data['faults'])) {
+ foreach ($alert_data['faults'] as $fault) {
+ $syslog_msg = $syslog_prefix . ' - ' . $fault['string'];
socket_sendto($socket, $syslog_msg, strlen($syslog_msg), 0, $syslog_host, $syslog_port);
}
- socket_close($socket);
+ } else {
+ $syslog_msg = $syslog_prefix;
+ socket_sendto($socket, $syslog_msg, strlen($syslog_msg), 0, $syslog_host, $syslog_port);
}
+ socket_close($socket);
return true;
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
@@ -158,9 +139,9 @@ class Syslog extends Transport
],
],
'validation' => [
- 'syslog-host' => 'required|string',
- 'syslog-port' => 'required|numeric',
- 'syslog-facility' => 'required|string',
+ 'syslog-host' => 'required|ip_or_hostname',
+ 'syslog-port' => 'required|integer|between:1,65536',
+ 'syslog-facility' => 'required|integer|between:0,23',
],
];
}
diff --git a/LibreNMS/Alert/Transport/Telegram.php b/LibreNMS/Alert/Transport/Telegram.php
index d4a5e5d15b..a20841aa0d 100644
--- a/LibreNMS/Alert/Transport/Telegram.php
+++ b/LibreNMS/Alert/Transport/Telegram.php
@@ -26,51 +26,42 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Telegram extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $telegram_opts['chat_id'] = $this->config['telegram-chat-id'];
- $telegram_opts['message_thread_id'] = $this->config['message-thread-id'] ?? null;
- $telegram_opts['token'] = $this->config['telegram-token'];
- $telegram_opts['format'] = $this->config['telegram-format'];
+ $url = "https://api.telegram.org/bot{$this->config['telegram-token']}/sendMessage";
+ $format = $this->config['telegram-format'];
+ $text = $format == 'Markdown'
+ ? preg_replace('/([a-z0-9]+)_([a-z0-9]+)/', "$1\_$2", $alert_data['msg'])
+ : $alert_data['msg'];
- return $this->contactTelegram($obj, $telegram_opts);
+ $params = [
+ 'chat_id' => $this->config['telegram-chat-id'],
+ 'text' => $text,
+ ];
+
+ if ($format) {
+ $params['format'] = $this->config['telegram-format'];
+ }
+
+ if (! empty($this->config['message-thread-id'])) {
+ $params['message_thread_id'] = $this->config['message-thread-id'];
+ }
+
+ $res = Http::client()->get($url, $params);
+
+ if ($res->successful()) {
+ return true;
+ }
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $text, $params);
}
- public static function contactTelegram($obj, $data)
- {
- $curl = curl_init();
- Proxy::applyToCurl($curl);
- $text = urlencode($obj['msg']);
- $format = '';
- if ($data['format']) {
- $format = '&parse_mode=' . $data['format'];
- if ($data['format'] == 'Markdown') {
- $text = urlencode(preg_replace('/([a-z0-9]+)_([a-z0-9]+)/', "$1\_$2", $obj['msg']));
- }
- }
- $messageThreadId = '';
- if (! empty($data['message_thread_id'])) {
- $messageThreadId = '&message_thread_id=' . $data['message_thread_id'];
- }
- curl_setopt($curl, CURLOPT_URL, "https://api.telegram.org/bot{$data['token']}/sendMessage?chat_id={$data['chat_id']}$messageThreadId&text=$text{$format}");
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code != 200) {
- var_dump('Telegram returned Error'); //FIXME: propper debuging
- var_dump('Return: ' . $ret); //FIXME: propper debuging
-
- return 'HTTP Status code ' . $code . ', Body ' . $ret;
- }
-
- return true;
- }
-
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Twilio.php b/LibreNMS/Alert/Transport/Twilio.php
index 7f88783305..e6ea1e7285 100644
--- a/LibreNMS/Alert/Transport/Twilio.php
+++ b/LibreNMS/Alert/Transport/Twilio.php
@@ -16,58 +16,33 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Twilio extends Transport
{
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- $twilio_opts['sid'] = $this->config['twilio-sid'];
- $twilio_opts['token'] = $this->config['twilio-token'];
- $twilio_opts['sender'] = $this->config['twilio-sender'];
- $twilio_opts['to'] = $this->config['twilio-to'];
-
- return $this->contactTwilio($obj, $twilio_opts);
- }
-
- public static function contactTwilio($obj, $opts)
- {
- $params = [
- 'sid' => $opts['sid'],
- 'token' => $opts['token'],
- 'phone' => $opts['to'],
- 'text' => $obj['msg'],
- 'sender' => $opts['sender'],
- ];
-
- $url = 'https://api.twilio.com/2010-04-01/Accounts/' . $params['sid'] . '/Messages.json';
+ $url = 'https://api.twilio.com/2010-04-01/Accounts/' . $this->config['twilio-sid'] . '/Messages.json';
$data = [
- 'From' => $params['sender'],
- 'Body' => $params['text'],
- 'To' => $params['phone'],
+ 'From' => $this->config['twilio-sender'],
+ 'Body' => $alert_data['msg'],
+ 'To' => $this->config['twilio-to'],
];
- $post = http_build_query($data);
- $curl = curl_init($url);
+ $res = Http::client()->asForm()
+ ->withBasicAuth($this->config['twilio-sid'], $this->config['twilio-token'])
+ ->post($url, $data);
- Proxy::applyToCurl($curl);
-
- curl_setopt($curl, CURLOPT_POST, true);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_setopt($curl, CURLOPT_USERPWD, $params['sid'] . ':' . $params['token']);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
-
- curl_exec($curl);
-
- if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE)) {
+ if ($res->successful()) {
return true;
}
+
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $data);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Ukfastpss.php b/LibreNMS/Alert/Transport/Ukfastpss.php
index 61b6037b77..d51857aa64 100644
--- a/LibreNMS/Alert/Transport/Ukfastpss.php
+++ b/LibreNMS/Alert/Transport/Ukfastpss.php
@@ -24,18 +24,14 @@
namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Ukfastpss extends Transport
{
- protected $name = 'UKFast PSS';
+ protected string $name = 'UKFast PSS';
- public function deliverAlert($obj, $opts)
- {
- return $this->contactUkfastpss($obj, $opts);
- }
-
- public function contactUkfastpss($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
$apiKey = $this->config['api-key'];
$author = $this->config['author'];
@@ -47,34 +43,27 @@ class Ukfastpss extends Transport
'id' => $author,
],
'secure' => ($secure == 'on'),
- 'subject' => $obj['title'],
- 'details' => $obj['msg'],
+ 'subject' => $alert_data['title'],
+ 'details' => $alert_data['msg'],
'priority' => $priority,
];
- $request_opts = [];
- $request_headers = [];
+ $res = Http::client()
+ ->withHeaders([
+ 'Authorization' => $apiKey,
+ 'Content-Type' => 'application/json',
+ 'Accept' => 'application/json',
+ ])
+ ->post('https://api.ukfast.io/pss/v1/requests', $body);
- $request_headers['Authorization'] = $apiKey;
- $request_headers['Content-Type'] = 'application/json';
- $request_headers['Accept'] = 'application/json';
-
- $client = new \GuzzleHttp\Client();
- $request_opts['proxy'] = Proxy::forGuzzle();
- $request_opts['headers'] = $request_headers;
- $request_opts['body'] = json_encode($body);
-
- $res = $client->request('POST', 'https://api.ukfast.io/pss/v1/requests', $request_opts);
-
- $code = $res->getStatusCode();
- if ($code != 200) {
- return 'HTTP Status code ' . $code;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $body);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Alert/Transport/Victorops.php b/LibreNMS/Alert/Transport/Victorops.php
index 7bbe26c164..c0f1ee0e85 100644
--- a/LibreNMS/Alert/Transport/Victorops.php
+++ b/LibreNMS/Alert/Transport/Victorops.php
@@ -26,62 +26,47 @@ namespace LibreNMS\Alert\Transport;
use LibreNMS\Alert\Transport;
use LibreNMS\Enum\AlertState;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Exceptions\AlertTransportDeliveryException;
+use LibreNMS\Util\Http;
class Victorops extends Transport
{
- protected $name = 'VictorOps';
+ protected string $name = 'Splunk On-Call';
- public function deliverAlert($obj, $opts)
+ public function deliverAlert(array $alert_data): bool
{
- if (! empty($this->config)) {
- $opts['url'] = $this->config['victorops-url'];
- }
-
- return $this->contactVictorops($obj, $opts);
- }
-
- public function contactVictorops($obj, $opts)
- {
- $url = $opts['url'];
-
+ $url = $this->config['victorops-url'];
$protocol = [
- 'entity_id' => strval($obj['id'] ? $obj['id'] : $obj['uid']),
- 'state_start_time' => strtotime($obj['timestamp']),
- 'entity_display_name' => $obj['title'],
- 'state_message' => $obj['msg'],
+ 'entity_id' => strval($alert_data['id'] ?: $alert_data['uid']),
+ 'state_start_time' => strtotime($alert_data['timestamp']),
+ 'entity_display_name' => $alert_data['title'],
+ 'state_message' => $alert_data['msg'],
'monitoring_tool' => 'librenms',
];
- if ($obj['state'] == AlertState::RECOVERED) {
- $protocol['message_type'] = 'recovery';
- } elseif ($obj['state'] == AlertState::ACKNOWLEDGED) {
- $protocol['message_type'] = 'acknowledgement';
- } elseif ($obj['state'] == AlertState::ACTIVE) {
- $protocol['message_type'] = 'critical';
- }
+ $protocol['message_type'] = match ($alert_data['state']) {
+ AlertState::RECOVERED => 'RECOVERY',
+ AlertState::ACKNOWLEDGED => 'ACKNOWLEDGEMENT',
+ default => match ($alert_data['severity']) {
+ 'ok' => 'INFO',
+ 'warning' => 'WARNING',
+ default => 'CRITICAL',
+ },
+ };
- foreach ($obj['faults'] as $fault => $data) {
+ foreach ($alert_data['faults'] as $fault => $data) {
$protocol['state_message'] .= $data['string'];
}
- $curl = curl_init();
- Proxy::applyToCurl($curl);
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-type' => 'application/json']);
- curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($protocol));
- $ret = curl_exec($curl);
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- if ($code != 200) {
- var_dump('VictorOps returned Error, retry later'); //FIXME: propper debuging
+ $res = Http::client()->post($url, $protocol);
- return false;
+ if ($res->successful()) {
+ return true;
}
- return true;
+ throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $protocol);
}
- public static function configTemplate()
+ public static function configTemplate(): array
{
return [
'config' => [
diff --git a/LibreNMS/Data/Store/Prometheus.php b/LibreNMS/Data/Store/Prometheus.php
index ef9ecc6de4..6e6ed5dc4c 100644
--- a/LibreNMS/Data/Store/Prometheus.php
+++ b/LibreNMS/Data/Store/Prometheus.php
@@ -27,40 +27,34 @@
namespace LibreNMS\Data\Store;
use App\Polling\Measure\Measurement;
-use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Str;
use LibreNMS\Config;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Util\Http;
use Log;
class Prometheus extends BaseDatastore
{
private $client;
private $base_uri;
- private $default_opts;
+
private $enabled;
private $prefix;
- public function __construct(\GuzzleHttp\Client $client)
+ public function __construct()
{
parent::__construct();
- $this->client = $client;
$url = Config::get('prometheus.url');
$job = Config::get('prometheus.job', 'librenms');
$this->base_uri = "$url/metrics/job/$job/instance/";
+
+ $this->client = Http::client()->baseUrl($this->base_uri);
+
$this->prefix = Config::get('prometheus.prefix', '');
if ($this->prefix) {
$this->prefix = "$this->prefix" . '_';
}
- $this->default_opts = [
- 'headers' => ['Content-Type' => 'text/plain'],
- ];
- if ($proxy = Proxy::get($url)) {
- $this->default_opts['proxy'] = $proxy;
- }
-
$this->enabled = self::isEnabled();
}
@@ -82,52 +76,41 @@ class Prometheus extends BaseDatastore
return;
}
- try {
- $vals = '';
- $promtags = '/measurement/' . $measurement;
+ $vals = '';
+ $promtags = '/measurement/' . $measurement;
- foreach ($fields as $k => $v) {
- if ($v !== null) {
- $vals .= $this->prefix . "$k $v\n";
- }
+ foreach ($fields as $k => $v) {
+ if ($v !== null) {
+ $vals .= $this->prefix . "$k $v\n";
}
-
- foreach ($tags as $t => $v) {
- if ($v !== null) {
- $promtags .= (Str::contains($v, '/') ? "/$t@base64/" . base64_encode($v) : "/$t/$v");
- }
- }
- $options = $this->getDefaultOptions();
- $options['body'] = $vals;
-
- $promurl = $this->base_uri . $device['hostname'] . $promtags;
- if (Config::get('prometheus.attach_sysname', false)) {
- $promurl .= '/sysName/' . $device['sysName'];
- }
- $promurl = str_replace(' ', '-', $promurl); // Prometheus doesn't handle tags with spaces in url
-
- Log::debug("Prometheus put $promurl: ", [
- 'measurement' => $measurement,
- 'tags' => $tags,
- 'fields' => $fields,
- 'vals' => $vals,
- ]);
-
- $result = $this->client->request('POST', $promurl, $options);
-
- $this->recordStatistic($stat->end());
-
- if ($result->getStatusCode() !== 200) {
- Log::error('Prometheus Error: ' . $result->getReasonPhrase());
- }
- } catch (GuzzleException $e) {
- Log::error('Prometheus Exception: ' . $e->getMessage());
}
- }
- private function getDefaultOptions()
- {
- return $this->default_opts;
+ foreach ($tags as $t => $v) {
+ if ($v !== null) {
+ $promtags .= (Str::contains($v, '/') ? "/$t@base64/" . base64_encode($v) : "/$t/$v");
+ }
+ }
+
+ $promurl = $device['hostname'] . $promtags;
+ if (Config::get('prometheus.attach_sysname', false)) {
+ $promurl .= '/sysName/' . $device['sysName'];
+ }
+ $promurl = str_replace(' ', '-', $promurl); // Prometheus doesn't handle tags with spaces in url
+
+ Log::debug("Prometheus put $promurl: ", [
+ 'measurement' => $measurement,
+ 'tags' => $tags,
+ 'fields' => $fields,
+ 'vals' => $vals,
+ ]);
+
+ $result = $this->client->withBody($vals, 'text/plain')->post($promurl);
+
+ $this->recordStatistic($stat->end());
+
+ if (! $result->successful()) {
+ Log::error('Prometheus Error: ' . $result->body());
+ }
}
/**
diff --git a/LibreNMS/Exceptions/AlertTransportDeliveryException.php b/LibreNMS/Exceptions/AlertTransportDeliveryException.php
index 8e72eae5cb..4828885174 100644
--- a/LibreNMS/Exceptions/AlertTransportDeliveryException.php
+++ b/LibreNMS/Exceptions/AlertTransportDeliveryException.php
@@ -27,26 +27,13 @@ namespace LibreNMS\Exceptions;
class AlertTransportDeliveryException extends \Exception
{
- /** @var array */
- protected $params = [];
- /** @var string */
- protected $template = '';
- /** @var string */
- protected $response = '';
-
- /**
- * @param array $data
- * @param int $code
- * @param string $response
- * @param string $message
- * @param array $params
- */
- public function __construct($data, $code = 0, $response = '', $message = '', $params = [])
- {
- $this->params = $params;
- $this->template = $message;
- $this->response = $response;
-
+ public function __construct(
+ array $data,
+ int $code = 0,
+ protected string $response = '',
+ protected string $template = '',
+ protected array $params = []
+ ) {
$name = $data['transport_name'] ?? '';
$message = "Transport delivery failed with $code for $name: $response";
diff --git a/LibreNMS/Interfaces/Alert/Transport.php b/LibreNMS/Interfaces/Alert/Transport.php
index af1fe3b3f2..b03f712a57 100644
--- a/LibreNMS/Interfaces/Alert/Transport.php
+++ b/LibreNMS/Interfaces/Alert/Transport.php
@@ -36,17 +36,16 @@ interface Transport
* Gets called when an alert is sent
*
* @param array $alert_data An array created by DescribeAlert
- * @param array|true $opts The options from the alert_transports transport_config column
- * @return mixed Returns if the call was successful
+ * @return bool Returns true if the call was successful.
*
* @throws \LibreNMS\Exceptions\AlertTransportDeliveryException
*/
- public function deliverAlert($alert_data, $opts);
+ public function deliverAlert(array $alert_data): bool;
/**
* @return array
*/
- public static function configTemplate();
+ public static function configTemplate(): array;
/**
* Display the configuration details of this alert transport
diff --git a/LibreNMS/Util/Git.php b/LibreNMS/Util/Git.php
index 3a0956f200..348f86af43 100644
--- a/LibreNMS/Util/Git.php
+++ b/LibreNMS/Util/Git.php
@@ -196,7 +196,7 @@ class Git
return $this->cacheGet('remoteCommit', function () {
if ($this->isAvailable()) {
try {
- return (array) \Http::withOptions(['proxy' => Proxy::forGuzzle()])->get(Config::get('github_api') . 'commits/master')->json();
+ return (array) Http::client()->get(Config::get('github_api') . 'commits/master')->json();
} catch (ConnectionException $e) {
}
}
diff --git a/LibreNMS/Util/GitHub.php b/LibreNMS/Util/GitHub.php
index e98916e740..8b1e31d9c2 100644
--- a/LibreNMS/Util/GitHub.php
+++ b/LibreNMS/Util/GitHub.php
@@ -27,7 +27,6 @@
namespace LibreNMS\Util;
use Exception;
-use Illuminate\Support\Facades\Http;
class GitHub
{
@@ -112,7 +111,7 @@ class GitHub
*/
public function getRelease($tag)
{
- $release = Http::withHeaders($this->getHeaders())->get($this->github . "/releases/tags/$tag");
+ $release = Http::client()->withHeaders($this->getHeaders())->get($this->github . "/releases/tags/$tag");
return $release->json();
}
@@ -122,7 +121,7 @@ class GitHub
*/
public function getPullRequest()
{
- $pull_request = Http::withHeaders($this->getHeaders())->get($this->github . "/pulls/{$this->pr}");
+ $pull_request = Http::client()->withHeaders($this->getHeaders())->get($this->github . "/pulls/{$this->pr}");
$this->pr = $pull_request->json();
}
@@ -180,7 +179,7 @@ class GitHub
}
GRAPHQL;
- $prs = Http::withHeaders($this->getHeaders())->post($this->graphql, ['query' => $query]);
+ $prs = Http::client()->withHeaders($this->getHeaders())->post($this->graphql, ['query' => $query]);
$prs = $prs->json();
if (! isset($prs['data'])) {
var_dump($prs);
@@ -366,7 +365,7 @@ GRAPHQL;
$this->createChangelog(false);
}
- $release = Http::withHeaders($this->getHeaders())->post($this->github . '/releases', [
+ $release = Http::client()->withHeaders($this->getHeaders())->post($this->github . '/releases', [
'tag_name' => $this->tag,
'target_commitish' => $updated_sha,
'body' => $this->markdown,
@@ -422,10 +421,10 @@ GRAPHQL;
*/
private function pushFileContents($file, $contents, $message): string
{
- $existing = Http::withHeaders($this->getHeaders())->get($this->github . '/contents/' . $file);
+ $existing = Http::client()->withHeaders($this->getHeaders())->get($this->github . '/contents/' . $file);
$existing_sha = $existing->json()['sha'];
- $updated = Http::withHeaders($this->getHeaders())->put($this->github . '/contents/' . $file, [
+ $updated = Http::client()->withHeaders($this->getHeaders())->put($this->github . '/contents/' . $file, [
'message' => $message,
'content' => base64_encode($contents),
'sha' => $existing_sha,
diff --git a/LibreNMS/Util/Http.php b/LibreNMS/Util/Http.php
new file mode 100644
index 0000000000..074dcea13e
--- /dev/null
+++ b/LibreNMS/Util/Http.php
@@ -0,0 +1,49 @@
+.
+ *
+ * @link https://www.librenms.org
+ *
+ * @copyright 2022 Tony Murray
+ * @author Tony Murray
+ */
+
+namespace LibreNMS\Util;
+
+use Illuminate\Http\Client\PendingRequest;
+use Illuminate\Support\Facades\Http as LaravelHttp;
+use LibreNMS\Config;
+
+class Http
+{
+ /**
+ * Create a new client with proxy set if appropriate and a distinct User-Agent header
+ */
+ public static function client(): PendingRequest
+ {
+ return LaravelHttp::withOptions([
+ 'proxy' => [
+ 'http' => Proxy::http(),
+ 'https' => Proxy::https(),
+ 'no' => Proxy::ignore(),
+ ],
+ ])->withHeaders([
+ 'User-Agent' => Config::get('project_name') . '/' . Version::VERSION, // we don't need fine version here, just rough
+ ]);
+ }
+}
diff --git a/LibreNMS/Util/Proxy.php b/LibreNMS/Util/Proxy.php
index d99dcd7993..3eeacca029 100644
--- a/LibreNMS/Util/Proxy.php
+++ b/LibreNMS/Util/Proxy.php
@@ -29,67 +29,29 @@ use LibreNMS\Config;
class Proxy
{
- /**
- * Check if if the proxy should be used.
- * (it should not be used for connections to localhost)
- */
- public static function shouldBeUsed(string $target_url): bool
+ public static function http(): string
{
- return preg_match('#(^|://)(localhost|127\.|::1)#', $target_url) == 0;
+ // use local_only to avoid CVE-2016-5385
+ $http_proxy = getenv('http_proxy', local_only: true) ?: getenv('HTTP_PROXY', local_only: true) ?: Config::get('http_proxy', '');
+
+ return $http_proxy;
}
- /**
- * Return the proxy url
- *
- * @return array|bool|false|string
- */
- public static function get(?string $target_url = null)
+ public static function https(): string
{
- if ($target_url && ! self::shouldBeUsed($target_url)) {
- return false;
- } elseif (getenv('http_proxy')) {
- return getenv('http_proxy');
- } elseif (getenv('https_proxy')) {
- return getenv('https_proxy');
- } elseif ($callback_proxy = Config::get('callback_proxy')) {
- return $callback_proxy;
- } elseif ($http_proxy = Config::get('http_proxy')) {
- return $http_proxy;
+ // use local_only to avoid CVE-2016-5385
+ return getenv('https_proxy', local_only: true) ?: getenv('HTTPS_PROXY', local_only: true) ?: Config::get('https_proxy', '');
+ }
+
+ public static function ignore(): array
+ {
+ // use local_only to avoid CVE-2016-5385
+ $no_proxy = getenv('no_proxy', local_only: true) ?: getenv('NO_PROXY', local_only: true) ?: Config::get('no_proxy', '');
+
+ if ($no_proxy == '') {
+ return [];
}
- return false;
- }
-
- /**
- * Return the proxy url in guzzle format "http://127.0.0.1:8888"
- */
- public static function forGuzzle(?string $target_url = null): string
- {
- $proxy = self::forCurl($target_url);
-
- return empty($proxy) ? '' : ('http://' . $proxy);
- }
-
- /**
- * Get the ip and port of the proxy
- *
- * @return string
- */
- public static function forCurl(?string $target_url = null): string
- {
- return str_replace(['http://', 'https://'], '', rtrim(self::get($target_url), '/'));
- }
-
- /**
- * Set the proxy on a curl handle
- *
- * @param \CurlHandle $curl
- */
- public static function applyToCurl($curl): void
- {
- $proxy = self::forCurl();
- if (! empty($proxy)) {
- curl_setopt($curl, CURLOPT_PROXY, $proxy);
- }
+ return explode(',', str_replace(' ', '', $no_proxy));
}
}
diff --git a/LibreNMS/Util/Stats.php b/LibreNMS/Util/Stats.php
index 7559b71409..201dbed04d 100644
--- a/LibreNMS/Util/Stats.php
+++ b/LibreNMS/Util/Stats.php
@@ -38,7 +38,7 @@ class Stats
$stats = new static;
if ($stats->isEnabled()) {
- $response = \Http::withOptions(['proxy' => Proxy::forGuzzle()])
+ Http::client()
->asForm()
->post(\LibreNMS\Config::get('callback_post'), [
'data' => json_encode($stats->collectData()),
@@ -63,7 +63,7 @@ class Stats
{
$uuid = Callback::get('uuid');
- $response = \Http::withOptions(['proxy' => Proxy::forGuzzle()])
+ $response = Http::client()
->asForm()
->post(\LibreNMS\Config::get('callback_clear'), ['uuid' => $uuid]);
diff --git a/app/ApiClients/BaseApi.php b/app/ApiClients/BaseApi.php
index 44f1bbf78e..d9ebfdc78e 100644
--- a/app/ApiClients/BaseApi.php
+++ b/app/ApiClients/BaseApi.php
@@ -25,8 +25,7 @@
namespace App\ApiClients;
-use Illuminate\Support\Facades\Http;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Util\Http;
class BaseApi
{
@@ -37,9 +36,7 @@ class BaseApi
protected function getClient(): \Illuminate\Http\Client\PendingRequest
{
if (is_null($this->client)) {
- $this->client = Http::withOptions([
- 'proxy' => Proxy::forGuzzle($this->base_uri),
- ])->baseUrl($this->base_uri)
+ $this->client = Http::client()->baseUrl($this->base_uri)
->timeout($this->timeout);
}
diff --git a/app/ApiClients/BingApi.php b/app/ApiClients/BingApi.php
index 63ae997022..1f3733dc72 100644
--- a/app/ApiClients/BingApi.php
+++ b/app/ApiClients/BingApi.php
@@ -49,7 +49,7 @@ class BingApi extends BaseApi implements Geocoder
}
/**
- * Build Guzzle request option array
+ * Build request option array
*
* @throws \Exception you may throw an Exception if validation fails
*/
diff --git a/app/ApiClients/GeocodingHelper.php b/app/ApiClients/GeocodingHelper.php
index 8f2460b15a..967c5c36c2 100644
--- a/app/ApiClients/GeocodingHelper.php
+++ b/app/ApiClients/GeocodingHelper.php
@@ -83,7 +83,7 @@ trait GeocodingHelper
abstract protected function parseLatLng(array $data): array;
/**
- * Build Guzzle request option array
+ * Build request option array
*
* @param string $address
* @return array
diff --git a/app/ApiClients/GoogleMapsApi.php b/app/ApiClients/GoogleMapsApi.php
index 564ffd22f5..f3c5c53538 100644
--- a/app/ApiClients/GoogleMapsApi.php
+++ b/app/ApiClients/GoogleMapsApi.php
@@ -60,7 +60,7 @@ class GoogleMapsApi extends BaseApi implements Geocoder
}
/**
- * Build Guzzle request option array
+ * Build request option array
*
* @throws \Exception you may throw an Exception if validation fails
*/
diff --git a/app/ApiClients/GraylogApi.php b/app/ApiClients/GraylogApi.php
index d0831a4fa1..ad69b291b8 100644
--- a/app/ApiClients/GraylogApi.php
+++ b/app/ApiClients/GraylogApi.php
@@ -26,12 +26,12 @@
namespace App\ApiClients;
use App\Models\Device;
-use GuzzleHttp\Client;
use LibreNMS\Config;
+use LibreNMS\Util\Http;
class GraylogApi
{
- private Client $client;
+ private \Illuminate\Http\Client\PendingRequest $client;
private string $api_prefix = '';
public function __construct(array $config = [])
@@ -53,7 +53,7 @@ class GraylogApi
];
}
- $this->client = new Client($config);
+ $this->client = Http::client()->withOptions($config);
}
public function getStreams(): array
@@ -65,9 +65,8 @@ class GraylogApi
$uri = $this->api_prefix . '/streams';
$response = $this->client->get($uri);
- $data = json_decode($response->getBody(), true);
- return $data ?: [];
+ return $response->json() ?: [];
}
/**
@@ -93,10 +92,9 @@ class GraylogApi
'filter' => $filter,
];
- $response = $this->client->get($uri, ['query' => $data]);
- $data = json_decode($response->getBody(), true);
+ $response = $this->client->get($uri, $data);
- return $data ?: [];
+ return $response->json() ?: [];
}
/**
diff --git a/app/ApiClients/MapquestApi.php b/app/ApiClients/MapquestApi.php
index cb7c52459a..74a9c3f66c 100644
--- a/app/ApiClients/MapquestApi.php
+++ b/app/ApiClients/MapquestApi.php
@@ -49,7 +49,7 @@ class MapquestApi extends BaseApi implements Geocoder
}
/**
- * Build Guzzle request option array
+ * Build request option array
*
* @throws \Exception you may throw an Exception if validation fails
*/
diff --git a/app/ApiClients/NominatimApi.php b/app/ApiClients/NominatimApi.php
index 56929eff17..c72c1fd62d 100644
--- a/app/ApiClients/NominatimApi.php
+++ b/app/ApiClients/NominatimApi.php
@@ -46,7 +46,7 @@ class NominatimApi extends BaseApi implements Geocoder
}
/**
- * Build Guzzle request option array
+ * Build request option array
*
* @throws \Exception you may throw an Exception if validation fails
*/
diff --git a/app/ApiClients/RipeApi.php b/app/ApiClients/RipeApi.php
index 7553ede752..b785403d2a 100644
--- a/app/ApiClients/RipeApi.php
+++ b/app/ApiClients/RipeApi.php
@@ -25,7 +25,6 @@
namespace App\ApiClients;
-use GuzzleHttp\Exception\RequestException;
use LibreNMS\Exceptions\ApiClientException;
class RipeApi extends BaseApi
@@ -68,21 +67,12 @@ class RipeApi extends BaseApi
*/
private function makeApiCall(string $uri, array $options): mixed
{
- try {
- $response_data = $this->getClient()->get($uri, $options['query'])->json();
- if (isset($response_data['status']) && $response_data['status'] == 'ok') {
- return $response_data;
- } else {
- throw new ApiClientException('RIPE API call failed', $response_data);
- }
- } catch (RequestException $e) {
- $message = 'RIPE API call to ' . $e->getRequest()->getUri() . ' failed: ';
- $message .= $e->getResponse()->getReasonPhrase() . ' ' . $e->getResponse()->getStatusCode();
+ $response_data = $this->getClient()->get($uri, $options['query'])->json();
- throw new ApiClientException(
- $message,
- json_decode($e->getResponse()->getBody(), true)
- );
+ if (isset($response_data['status']) && $response_data['status'] == 'ok') {
+ return $response_data;
}
+
+ throw new ApiClientException("RIPE API call to $this->base_uri/$uri failed: " . $this->getClient()->get($uri, $options['query'])->status(), $response_data);
}
}
diff --git a/app/Http/Controllers/AboutController.php b/app/Http/Controllers/AboutController.php
index 0030a7fd49..634a7a87ec 100644
--- a/app/Http/Controllers/AboutController.php
+++ b/app/Http/Controllers/AboutController.php
@@ -54,6 +54,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use LibreNMS\Config;
use LibreNMS\Data\Store\Rrd;
+use LibreNMS\Util\Http;
use LibreNMS\Util\Version;
class AboutController extends Controller
@@ -113,7 +114,7 @@ class AboutController extends Controller
// try to clear usage data if we have a uuid
if ($usage_uuid) {
- if (! \Http::post(Config::get('callback_clear'), ['uuid' => $usage_uuid])->successful()) {
+ if (! Http::client()->post(Config::get('callback_clear'), ['uuid' => $usage_uuid])->successful()) {
return response()->json([], 500); // don't clear if this fails to delete upstream data
}
}
diff --git a/app/Http/Controllers/AlertTransportController.php b/app/Http/Controllers/AlertTransportController.php
index d5fdc3c49b..221e560a1b 100644
--- a/app/Http/Controllers/AlertTransportController.php
+++ b/app/Http/Controllers/AlertTransportController.php
@@ -5,41 +5,19 @@ namespace App\Http\Controllers;
use App\Models\AlertTransport;
use App\Models\Device;
use Illuminate\Http\Request;
-use LibreNMS\Alert\AlertUtil;
-use LibreNMS\Config;
+use LibreNMS\Alert\AlertData;
use LibreNMS\Exceptions\AlertTransportDeliveryException;
class AlertTransportController extends Controller
{
public function test(Request $request, AlertTransport $transport): \Illuminate\Http\JsonResponse
{
+ /** @var Device $device */
$device = Device::with('location')->first();
- $obj = [
- 'hostname' => $device->hostname,
- 'device_id' => $device->device_id,
- 'sysDescr' => $device->sysDescr,
- 'version' => $device->version,
- 'hardware' => $device->hardware,
- 'location' => $device->location,
- 'title' => 'Testing transport from ' . Config::get('project_name'),
- 'elapsed' => '11s',
- 'alert_id' => '000',
- 'id' => '000',
- 'faults' => [],
- 'uid' => '000',
- 'severity' => 'critical',
- 'rule' => 'macros.device = 1',
- 'name' => 'Test-Rule',
- 'string' => '#1: test => string;',
- 'timestamp' => date('Y-m-d H:i:s'),
- 'contacts' => AlertUtil::getContacts($device->toArray()),
- 'state' => '1',
- 'msg' => 'This is a test alert',
- ];
+ $alert_data = AlertData::testData($device);
- $opts = Config::get('alert.transports.' . $transport->transport_type);
try {
- $result = $transport->instance()->deliverAlert($obj, $opts);
+ $result = $transport->instance()->deliverAlert($alert_data);
if ($result === true) {
return response()->json(['status' => 'ok']);
@@ -47,7 +25,7 @@ class AlertTransportController extends Controller
} catch (AlertTransportDeliveryException $e) {
return response()->json([
'status' => 'error',
- 'message' => $e->getMessage(),
+ 'message' => strip_tags($e->getMessage()),
]);
} catch (\Exception $e) {
\Log::error($e);
@@ -56,7 +34,7 @@ class AlertTransportController extends Controller
return response()->json([
'status' => 'error',
- 'message' => $result,
+ 'message' => strip_tags($result),
]);
}
}
diff --git a/app/Models/AlertTransport.php b/app/Models/AlertTransport.php
index b299e39fff..7b7c2f9bb3 100644
--- a/app/Models/AlertTransport.php
+++ b/app/Models/AlertTransport.php
@@ -5,27 +5,8 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use LibreNMS\Alert\Transport;
+use LibreNMS\Alert\Transport\Dummy;
-/**
- * \App\Models\AlertTransport
- *
- * @property int $transport_id
- * @property string $transport_name
- * @property string $transport_type
- * @property bool $is_default
- * @property array|null $transport_config
- *
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport newModelQuery()
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport newQuery()
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport query()
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereIsDefault($value)
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportConfig($value)
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportId($value)
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportName($value)
- * @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportType($value)
- *
- * @mixin \Eloquent
- */
class AlertTransport extends Model
{
use HasFactory;
@@ -36,11 +17,16 @@ class AlertTransport extends Model
'is_default' => 'boolean',
'transport_config' => 'array',
];
+ protected $fillable = ['transport_config'];
public function instance(): Transport
{
$class = Transport::getClass($this->transport_type);
- return new $class($this);
+ if (class_exists($class)) {
+ return new $class($this);
+ }
+
+ return new Dummy;
}
}
diff --git a/composer.json b/composer.json
index 0d5c3814cc..f032f75588 100644
--- a/composer.json
+++ b/composer.json
@@ -32,7 +32,6 @@
"easybook/geshi": "^1.0.8",
"ezyang/htmlpurifier": "^4.8",
"fico7489/laravel-pivot": "^3.0",
- "guzzlehttp/guzzle": "^7.2",
"influxdb/influxdb-php": "^1.15",
"justinrainbow/json-schema": "^5.2",
"laravel-notification-channels/webpush": "^7.0",
diff --git a/composer.lock b/composer.lock
index 6483e7e748..04c927834f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "9921ea55b62f77f05208738b5b783b31",
+ "content-hash": "4a8a1c7d52ce1cb29b37826a53d89804",
"packages": [
{
"name": "amenadiel/jpgraph",
diff --git a/config/app.php b/config/app.php
index f898df2673..97e6c10777 100644
--- a/config/app.php
+++ b/config/app.php
@@ -233,6 +233,8 @@ return [
'PluginManager' => \App\Facades\PluginManager::class,
'Rrd' => \App\Facades\Rrd::class,
'SnmpQuery' => \App\Facades\FacadeAccessorSnmp::class,
+ ])->forget([
+ 'Http', // don't use Laravel Http facade, LibreNMS has its own wrapper
])->toArray(),
'charset' => env('CHARSET', ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'),
diff --git a/doc/Alerting/Transports.md b/doc/Alerting/Transports.md
index 35f7ce3919..de84de6c61 100644
--- a/doc/Alerting/Transports.md
+++ b/doc/Alerting/Transports.md
@@ -183,19 +183,6 @@ You need a token you can find on your personnal space.
| API URL | https://soap.aspsms.com/aspsmsx.asmx/SimpleTextSMS |
| Options | UserKey=USERKEY
Password=APIPASSWORD
Recipient=RECIPIENT
Originator=ORIGINATOR
MessageText={{ $msg }} |
-## Boxcar
-
-Copy your access token from the Boxcar app or from the Boxcar.io
-website and setup the transport.
-
-[Boxcar Docs](http://developer.boxcar.io/api/publisher/)
-
-**Example:**
-
-| Config | Example |
-| ------ | ------- |
-| Access Token | i23f23mr23rwerw |
-
## Browser Push
Browser push notifications can send a notification to the user's
@@ -322,9 +309,9 @@ for details on acceptable values.
| API URL | |
| Room ID | 7654321 |
| From Name | LibreNMS |
-| Options | color = red
notify = 1
message_format = text |
+| Options | color=red |
-At present the following options are supported: `color`, `notify` and `message_format`.
+At present the following options are supported: `color`.
> Note: The default message format for HipChat messages is HTML. It is
> recommended that you specify the `text` message format to prevent unexpected
@@ -536,7 +523,7 @@ Here an example using 3 numbers, any amount of numbers is supported:
| Config | Example |
| ------ | ------- |
-| PlaySMS | |
+| PlaySMS | |
| User | user1 |
| Token | MYFANCYACCESSTOKEN |
| From | My Name |
diff --git a/includes/functions.php b/includes/functions.php
index 18beee5a50..0b35a8bec0 100644
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -9,7 +9,6 @@
*/
use App\Models\Device;
-use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use LibreNMS\Config;
use LibreNMS\Enum\PortAssociationMode;
@@ -23,7 +22,6 @@ use LibreNMS\Exceptions\HostUnreachableSnmpException;
use LibreNMS\Exceptions\InvalidPortAssocModeException;
use LibreNMS\Exceptions\SnmpVersionUnsupportedException;
use LibreNMS\Modules\Core;
-use LibreNMS\Util\Proxy;
function array_sort_by_column($array, $on, $order = SORT_ASC)
{
@@ -759,14 +757,6 @@ function guidv4($data)
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
-/**
- * @param $curl
- */
-function set_curl_proxy($curl)
-{
- \LibreNMS\Util\Proxy::applyToCurl($curl);
-}
-
function target_to_id($target)
{
if ($target[0] . $target[1] == 'g:') {
@@ -1197,7 +1187,7 @@ function cache_mac_oui()
//$mac_oui_url_mirror = 'https://raw.githubusercontent.com/wireshark/wireshark/master/manuf';
echo ' -> Downloading ...' . PHP_EOL;
- $get = Http::withOptions(['proxy' => Proxy::forGuzzle()])->get($mac_oui_url);
+ $get = \LibreNMS\Util\Http::client()->get($mac_oui_url);
echo ' -> Processing CSV ...' . PHP_EOL;
$csv_data = $get->body();
foreach (explode("\n", $csv_data) as $csv_line) {
@@ -1255,7 +1245,7 @@ function cache_peeringdb()
$ix_keep = [];
foreach (dbFetchRows('SELECT `bgpLocalAs` FROM `devices` WHERE `disabled` = 0 AND `ignore` = 0 AND `bgpLocalAs` > 0 AND (`bgpLocalAs` < 64512 OR `bgpLocalAs` > 65535) AND `bgpLocalAs` < 4200000000 GROUP BY `bgpLocalAs`') as $as) {
$asn = $as['bgpLocalAs'];
- $get = Http::withOptions(['proxy' => Proxy::forGuzzle()])->get($peeringdb_url . '/net?depth=2&asn=' . $asn);
+ $get = \LibreNMS\Util\Http::client()->get($peeringdb_url . '/net?depth=2&asn=' . $asn);
$json_data = $get->body();
$data = json_decode($json_data);
$ixs = $data->{'data'}[0]->{'netixlan_set'};
@@ -1276,7 +1266,7 @@ function cache_peeringdb()
$pdb_ix_id = dbInsert($insert, 'pdb_ix');
}
$ix_keep[] = $pdb_ix_id;
- $get_ix = Http::withOptions(['proxy' => Proxy::forGuzzle()])->get("$peeringdb_url/netixlan?ix_id=$ixid");
+ $get_ix = \LibreNMS\Util\Http::client()->get("$peeringdb_url/netixlan?ix_id=$ixid");
$ix_json = $get_ix->body();
$ix_data = json_decode($ix_json);
$peers = $ix_data->{'data'};
diff --git a/lang/en/settings.php b/lang/en/settings.php
index 6750e1e568..7018eba88b 100644
--- a/lang/en/settings.php
+++ b/lang/en/settings.php
@@ -823,8 +823,12 @@ return [
'help' => 'Can be a ENV or HTTP-header field like REMOTE_USER, PHP_AUTH_USER or a custom variant',
],
'http_proxy' => [
- 'description' => 'HTTP(S) Proxy',
- 'help' => 'Set this as a fallback if http_proxy or https_proxy environment variable is not available.',
+ 'description' => 'HTTP Proxy',
+ 'help' => 'Set this as a fallback if http_proxy environment variable is not available.',
+ ],
+ 'https_proxy' => [
+ 'description' => 'HTTPS Proxy',
+ 'help' => 'Set this as a fallback if https_proxy environment variable is not available.',
],
'ignore_mount' => [
'description' => 'Mountpoints to be ignored',
@@ -968,6 +972,10 @@ return [
'nmap' => [
'description' => 'Path to nmap',
],
+ 'no_proxy' => [
+ 'description' => 'Proxy Exceptions',
+ 'help' => 'Set this as a fallback if no_proxy environment variable is not available. Comma seperated list of IPs, hosts or domains to ignore.',
+ ],
'opentsdb' => [
'enable' => [
'description' => 'Enable',
diff --git a/misc/config_definitions.json b/misc/config_definitions.json
index 54cb149cb5..f633aa9bb1 100644
--- a/misc/config_definitions.json
+++ b/misc/config_definitions.json
@@ -3757,7 +3757,25 @@
"group": "system",
"section": "proxy",
"order": 0,
- "type": "text"
+ "type": "text",
+ "validate": {
+ "value": [
+ "nullable",
+ "starts_with:http://,https://,tcp://"
+ ]
+ }
+ },
+ "https_proxy": {
+ "group": "system",
+ "section": "proxy",
+ "order": 1,
+ "type": "text",
+ "validate": {
+ "value": [
+ "nullable",
+ "starts_with:http://,https://,tcp://"
+ ]
+ }
},
"icmp_check": {
"default": true,
@@ -4352,6 +4370,13 @@
"order": 5,
"type": "executable"
},
+ "no_proxy": {
+ "group": "system",
+ "default": "localhost,127.0.0.1,::1",
+ "section": "proxy",
+ "order": 2,
+ "type": "text"
+ },
"notifications.LibreNMS": {
"default": "https://www.librenms.org/notifications.rss",
"type": "text"
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index cf09cd450e..97b853db8b 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -1,10 +1,5 @@
parameters:
ignoreErrors:
- -
- message: "#^Static property LibreNMS\\\\Alert\\\\Transport\\\\Sensu\\:\\:\\$severity is never read, only written\\.$#"
- count: 1
- path: LibreNMS/Alert/Transport/Sensu.php
-
-
message: "#^If condition is always false\\.$#"
count: 1
diff --git a/tests/AlertingTest.php b/tests/AlertingTest.php
index baed674cbc..2ca517bad9 100644
--- a/tests/AlertingTest.php
+++ b/tests/AlertingTest.php
@@ -27,12 +27,11 @@ namespace LibreNMS\Tests;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
-use RecursiveRegexIterator;
use RegexIterator;
class AlertingTest extends TestCase
{
- public function testJsonAlertCollection()
+ public function testJsonAlertCollection(): void
{
$rules = get_rules_from_json();
$this->assertIsArray($rules);
@@ -41,7 +40,7 @@ class AlertingTest extends TestCase
}
}
- public function testTransports()
+ public function testTransports(): void
{
foreach ($this->getTransportFiles() as $file => $_unused) {
$parts = explode('/', $file);
@@ -52,10 +51,10 @@ class AlertingTest extends TestCase
}
}
- private function getTransportFiles()
+ private function getTransportFiles(): RegexIterator
{
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('LibreNMS/Alert/Transport'));
- return new RegexIterator($iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
+ return new RegexIterator($iterator, '/^.+\.php$/i', RegexIterator::GET_MATCH);
}
}
diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php
index 02d66eae1b..3291bc7d06 100644
--- a/tests/ProxyTest.php
+++ b/tests/ProxyTest.php
@@ -22,21 +22,70 @@
namespace LibreNMS\Tests;
-use LibreNMS\Util\Proxy;
+use LibreNMS\Config;
+use LibreNMS\Util\Http;
+use LibreNMS\Util\Version;
class ProxyTest extends TestCase
{
- public function testShouldBeUsed(): void
+ public function testClientAgentIsCorrect(): void
{
- $this->assertTrue(Proxy::shouldBeUsed('http://example.com/foobar'));
- $this->assertTrue(Proxy::shouldBeUsed('foo/bar'));
- $this->assertTrue(Proxy::shouldBeUsed('192.168.0.1'));
- $this->assertTrue(Proxy::shouldBeUsed('2001:db8::8a2e:370:7334'));
+ $this->assertEquals('LibreNMS/' . Version::VERSION, Http::client()->getOptions()['headers']['User-Agent']);
+ }
- $this->assertFalse(Proxy::shouldBeUsed('http://localhost/foobar'));
- $this->assertFalse(Proxy::shouldBeUsed('localhost/foobar'));
- $this->assertFalse(Proxy::shouldBeUsed('127.0.0.1'));
- $this->assertFalse(Proxy::shouldBeUsed('127.0.0.1:1337'));
- $this->assertFalse(Proxy::shouldBeUsed('::1'));
+ public function testProxyIsNotSet(): void
+ {
+ Config::set('http_proxy', '');
+ Config::set('https_proxy', '');
+ Config::set('no_proxy', '');
+ $client_options = Http::client()->getOptions();
+ $this->assertEmpty($client_options['proxy']['http']);
+ $this->assertEmpty($client_options['proxy']['https']);
+ $this->assertEmpty($client_options['proxy']['no']);
+ }
+
+ public function testProxyIsSet(): void
+ {
+ Config::set('http_proxy', 'http://proxy:5000');
+ Config::set('https_proxy', 'tcp://proxy:5183');
+ Config::set('no_proxy', 'localhost,127.0.0.1,::1,.domain.com');
+ $client_options = Http::client()->getOptions();
+ $this->assertEquals('http://proxy:5000', $client_options['proxy']['http']);
+ $this->assertEquals('tcp://proxy:5183', $client_options['proxy']['https']);
+ $this->assertEquals([
+ 'localhost',
+ '127.0.0.1',
+ '::1',
+ '.domain.com',
+ ], $client_options['proxy']['no']);
+ }
+
+ public function testProxyIsSetFromEnv(): void
+ {
+ Config::set('http_proxy', '');
+ Config::set('https_proxy', '');
+ Config::set('no_proxy', '');
+
+ putenv('HTTP_PROXY=someproxy:3182');
+ putenv('HTTPS_PROXY=https://someproxy:3182');
+ putenv('NO_PROXY=.there.com');
+
+ $client_options = Http::client()->getOptions();
+ $this->assertEquals('someproxy:3182', $client_options['proxy']['http']);
+ $this->assertEquals('https://someproxy:3182', $client_options['proxy']['https']);
+ $this->assertEquals([
+ '.there.com',
+ ], $client_options['proxy']['no']);
+
+ putenv('http_proxy=otherproxy:3182');
+ putenv('https_proxy=otherproxy:3183');
+ putenv('no_proxy=dontproxymebro');
+
+ $client_options = Http::client()->getOptions();
+ $this->assertEquals('otherproxy:3182', $client_options['proxy']['http']);
+ $this->assertEquals('otherproxy:3183', $client_options['proxy']['https']);
+ $this->assertEquals([
+ 'dontproxymebro',
+ ], $client_options['proxy']['no']);
}
}
diff --git a/tests/Traits/MockGuzzleClient.php b/tests/Traits/MockGuzzleClient.php
deleted file mode 100644
index 01a4d789e5..0000000000
--- a/tests/Traits/MockGuzzleClient.php
+++ /dev/null
@@ -1,80 +0,0 @@
-guzzleConfig = $config;
- $this->guzzleMockHandler = new MockHandler($queue);
-
- $this->app->bind(Client::class, function () {
- $handlerStack = HandlerStack::create($this->guzzleMockHandler);
- $handlerStack->push(Middleware::history($this->guzzleHistory));
-
- return new Client(array_merge($this->guzzleConfig, ['handler' => $handlerStack]));
- });
-
- return $this->guzzleMockHandler;
- }
-
- /**
- * Get the request and response history to inspect
- *
- * @return array
- */
- public function guzzleHistory(): array
- {
- return $this->guzzleHistory;
- }
-
- /**
- * Get the request history to inspect
- *
- * @return \GuzzleHttp\Psr7\Request[]
- */
- public function guzzleRequestHistory(): array
- {
- return array_column($this->guzzleHistory, 'request');
- }
-
- /**
- * Get the response history to inspect
- *
- * @return \GuzzleHttp\Psr7\Response[]
- */
- public function guzzleResponseHistory(): array
- {
- return array_column($this->guzzleHistory, 'response');
- }
-}
diff --git a/tests/Unit/Alert/Transports/SlackTest.php b/tests/Unit/Alert/Transports/SlackTest.php
new file mode 100644
index 0000000000..f6c17ac532
--- /dev/null
+++ b/tests/Unit/Alert/Transports/SlackTest.php
@@ -0,0 +1,155 @@
+.
+ *
+ * @link https://www.librenms.org
+ *
+ * @copyright 2022 Tony Murray
+ * @author Tony Murray
+ */
+
+namespace LibreNMS\Tests\Unit\Alert\Transports;
+
+use App\Models\AlertTransport;
+use App\Models\Device;
+use Illuminate\Http\Client\Request;
+use Illuminate\Support\Facades\Http;
+use LibreNMS\Alert\AlertData;
+use LibreNMS\Alert\Transport;
+use LibreNMS\Tests\TestCase;
+
+class SlackTest extends TestCase
+{
+ public function testSlackNoConfigDelivery(): void
+ {
+ Http::fake();
+
+ $slack = new Transport\Slack(new AlertTransport);
+
+ /** @var Device $mock_device */
+ $mock_device = Device::factory()->make();
+ $slack->deliverAlert(AlertData::testData($mock_device));
+
+ Http::assertSent(function (Request $request) {
+ return
+ $request->url() == '' &&
+ $request->method() == 'POST' &&
+ $request->hasHeader('Content-Type', 'application/json') &&
+ $request->data() == [
+ 'attachments' => [
+ [
+ 'fallback' => 'This is a test alert',
+ 'color' => '#ff0000',
+ 'title' => 'Testing transport from LibreNMS',
+ 'text' => 'This is a test alert',
+ 'mrkdwn_in' => [
+ 'text',
+ 'fallback',
+ ],
+ 'author_name' => null,
+ ],
+ ],
+ 'channel' => null,
+ 'icon_emoji' => null,
+ ];
+ });
+ }
+
+ public function testSlackLegacyDelivery(): void
+ {
+ Http::fake();
+
+ $slack = new Transport\Slack(new AlertTransport([
+ 'transport_config' => [
+ 'slack-url' => 'https://slack.com/some/webhook',
+ 'slack-options' => "icon_emoji=smile\nauthor=Me\nchannel=Alerts",
+ ],
+ ]));
+
+ /** @var Device $mock_device */
+ $mock_device = Device::factory()->make();
+ $slack->deliverAlert(AlertData::testData($mock_device));
+
+ Http::assertSent(function (Request $request) {
+ return
+ $request->url() == 'https://slack.com/some/webhook' &&
+ $request->method() == 'POST' &&
+ $request->hasHeader('Content-Type', 'application/json') &&
+ $request->data() == [
+ 'attachments' => [
+ [
+ 'fallback' => 'This is a test alert',
+ 'color' => '#ff0000',
+ 'title' => 'Testing transport from LibreNMS',
+ 'text' => 'This is a test alert',
+ 'mrkdwn_in' => [
+ 'text',
+ 'fallback',
+ ],
+ 'author_name' => 'Me',
+ ],
+ ],
+ 'channel' => 'Alerts',
+ 'icon_emoji' => ':smile:',
+ ];
+ });
+ }
+
+ public function testSlackDelivery(): void
+ {
+ Http::fake();
+
+ $slack = new Transport\Slack(new AlertTransport([
+ 'transport_config' => [
+ 'slack-url' => 'https://slack.com/some/webhook',
+ 'slack-options' => "icon_emoji=smile\nauthor=Me\nchannel=Alerts",
+ 'slack-icon_emoji' => ':slight_smile:',
+ 'slack-author' => 'Other',
+ 'slack-channel' => 'Critical',
+ ],
+ ]));
+
+ /** @var Device $mock_device */
+ $mock_device = Device::factory()->make();
+ $slack->deliverAlert(AlertData::testData($mock_device));
+
+ Http::assertSent(function (Request $request) {
+ return
+ $request->url() == 'https://slack.com/some/webhook' &&
+ $request->method() == 'POST' &&
+ $request->hasHeader('Content-Type', 'application/json') &&
+ $request->data() == [
+ 'attachments' => [
+ [
+ 'fallback' => 'This is a test alert',
+ 'color' => '#ff0000',
+ 'title' => 'Testing transport from LibreNMS',
+ 'text' => 'This is a test alert',
+ 'mrkdwn_in' => [
+ 'text',
+ 'fallback',
+ ],
+ 'author_name' => 'Other',
+ ],
+ ],
+ 'channel' => 'Critical',
+ 'icon_emoji' => ':slight_smile:',
+ ];
+ });
+ }
+}
diff --git a/tests/Unit/ApiTransportTest.php b/tests/Unit/ApiTransportTest.php
index f2469a380d..92fe82b4a3 100644
--- a/tests/Unit/ApiTransportTest.php
+++ b/tests/Unit/ApiTransportTest.php
@@ -3,34 +3,31 @@
namespace LibreNMS\Tests\Unit;
use App\Models\AlertTransport;
-use GuzzleHttp\Psr7\Response;
-use LibreNMS\Config;
+use Illuminate\Http\Client\Request;
+use Illuminate\Support\Facades\Http as LaravelHttp;
use LibreNMS\Tests\TestCase;
-use LibreNMS\Tests\Traits\MockGuzzleClient;
class ApiTransportTest extends TestCase
{
- use MockGuzzleClient;
-
public function testGetMultilineVariables(): void
{
/** @var AlertTransport $transport */
$transport = AlertTransport::factory()->api('text={{ $msg }}')->make();
- $this->mockGuzzleClient([
- new Response(200),
+ LaravelHttp::fake([
+ '*' => LaravelHttp::response(),
]);
$obj = ['msg' => "This is a multi-line\nalert."];
- $opts = Config::get('alert.transports.' . $transport->transport_type);
- $result = $transport->instance()->deliverAlert($obj, $opts);
+ $result = $transport->instance()->deliverAlert($obj);
$this->assertTrue($result);
- $history = $this->guzzleRequestHistory();
- $this->assertCount(1, $history);
- $this->assertEquals('GET', $history[0]->getMethod());
- $this->assertEquals('text=This%20is%20a%20multi-line%0Aalert.', $history[0]->getUri()->getQuery());
+ LaravelHttp::assertSentCount(1);
+ LaravelHttp::assertSent(function (Request $request) {
+ return $request->method() == 'GET' &&
+ $request->url() == 'https://librenms.org?text=This%20is%20a%20multi-line%0Aalert.';
+ });
}
public function testPostMultilineVariables(): void
@@ -42,21 +39,20 @@ class ApiTransportTest extends TestCase
'bodytext={{ $msg }}',
)->make();
- $this->mockGuzzleClient([
- new Response(200),
+ LaravelHttp::fake([
+ '*' => LaravelHttp::response(),
]);
$obj = ['msg' => "This is a post multi-line\nalert."];
- $opts = Config::get('alert.transports.' . $transport->transport_type);
- $result = $transport->instance()->deliverAlert($obj, $opts);
+ $result = $transport->instance()->deliverAlert($obj);
$this->assertTrue($result);
- $history = $this->guzzleRequestHistory();
- $this->assertCount(1, $history);
- $this->assertEquals('POST', $history[0]->getMethod());
- // FUBAR
- $this->assertEquals('text=This%20is%20a%20post%20multi-line%0Aalert.', $history[0]->getUri()->getQuery());
- $this->assertEquals("bodytext=This is a post multi-line\nalert.", (string) $history[0]->getBody());
+ LaravelHttp::assertSentCount(1);
+ LaravelHttp::assertSent(function (Request $request) {
+ return $request->method() == 'POST' &&
+ $request->url() == 'https://librenms.org?text=This%20is%20a%20post%20multi-line%0Aalert.' &&
+ $request->body() == "bodytext=This is a post multi-line\nalert.";
+ });
}
}
diff --git a/tests/Unit/Data/PrometheusStoreTest.php b/tests/Unit/Data/PrometheusStoreTest.php
index 03fa7920d9..7048faa986 100644
--- a/tests/Unit/Data/PrometheusStoreTest.php
+++ b/tests/Unit/Data/PrometheusStoreTest.php
@@ -25,21 +25,16 @@
namespace LibreNMS\Tests\Unit\Data;
-use GuzzleHttp\Exception\RequestException;
-use GuzzleHttp\Psr7\Request;
-use GuzzleHttp\Psr7\Response;
+use Illuminate\Support\Facades\Http as LaravelHttp;
use LibreNMS\Config;
use LibreNMS\Data\Store\Prometheus;
use LibreNMS\Tests\TestCase;
-use LibreNMS\Tests\Traits\MockGuzzleClient;
/**
* @group datastores
*/
class PrometheusStoreTest extends TestCase
{
- use MockGuzzleClient;
-
protected function setUp(): void
{
parent::setUp();
@@ -48,26 +43,20 @@ class PrometheusStoreTest extends TestCase
Config::set('prometheus.url', 'http://fake:9999');
}
- public function testFailWrite()
+ public function testFailWrite(): void
{
- $this->mockGuzzleClient([
- new Response(422, [], 'Bad response'),
- new RequestException('Exception thrown', new Request('POST', 'test')),
- ]);
-
+ LaravelHttp::fakeSequence()->push('Bad response', 422);
$prometheus = app(Prometheus::class);
\Log::shouldReceive('debug');
- \Log::shouldReceive('error')->once()->with("Prometheus Exception: Client error: `POST http://fake:9999/metrics/job/librenms/instance/test/measurement/none` resulted in a `422 Unprocessable Entity` response:\nBad response\n");
- \Log::shouldReceive('error')->once()->with('Prometheus Exception: Exception thrown');
- $prometheus->put(['hostname' => 'test'], 'none', [], ['one' => 1]);
+ \Log::shouldReceive('error')->once()->with('Prometheus Error: Bad response');
$prometheus->put(['hostname' => 'test'], 'none', [], ['one' => 1]);
}
- public function testSimpleWrite()
+ public function testSimpleWrite(): void
{
- $this->mockGuzzleClient([
- new Response(200),
+ LaravelHttp::fake([
+ '*' => LaravelHttp::response(),
]);
$prometheus = app(Prometheus::class);
@@ -82,12 +71,11 @@ class PrometheusStoreTest extends TestCase
$prometheus->put($device, $measurement, $tags, $fields);
- $history = $this->guzzleRequestHistory();
- $this->assertCount(1, $history, 'Did not receive the expected number of requests');
- $this->assertEquals('POST', $history[0]->getMethod());
- $this->assertEquals('/metrics/job/librenms/instance/testhost/measurement/testmeasure/ifName/testifname/type/testtype', $history[0]->getUri()->getPath());
- $this->assertEquals('fake', $history[0]->getUri()->getHost());
- $this->assertEquals(9999, $history[0]->getUri()->getPort());
- $this->assertEquals("ifIn 234234\nifOut 53453\n", (string) $history[0]->getBody());
+ LaravelHttp::assertSentCount(1);
+ LaravelHttp::assertSent(function (\Illuminate\Http\Client\Request $request) {
+ return $request->method() == 'POST' &&
+ $request->url() == 'http://fake:9999/metrics/job/librenms/instance/testhost/measurement/testmeasure/ifName/testifname/type/testtype' &&
+ $request->body() == "ifIn 234234\nifOut 53453\n";
+ });
}
}