Skip to content

Commit

Permalink
Merge branch 'librenms:master' into worknoc
Browse files Browse the repository at this point in the history
  • Loading branch information
ottorei authored Oct 8, 2024
2 parents 204d6fb + 915f39c commit 9683e9c
Show file tree
Hide file tree
Showing 301 changed files with 140,926 additions and 30,164 deletions.
2 changes: 1 addition & 1 deletion LibreNMS/Alert/Transport.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public function displayDetails(): string

$val = $this->config[$item['name']];
if ($item['type'] == 'password') {
$val = '<b>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;</b>';
$val = '********';
} elseif ($item['type'] == 'select') {
// Match value to key name for select inputs
$val = array_search($val, $item['options']);
Expand Down
133 changes: 99 additions & 34 deletions LibreNMS/Alert/Transport/Discord.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Discord.php
*
Expand Down Expand Up @@ -35,76 +36,141 @@

class Discord extends Transport
{
public const DEFAULT_EMBEDS = 'hostname,name,timestamp,severity';
private array $embedFieldTranslations = [
'name' => 'Rule Name',
];

private array $discord_message = [];

/**
* Composes a Discord JSON message and delivers it using HTTP POST
* https://discord.com/developers/docs/resources/message#create-message
*
* @param array $alert_data
* @return bool
*/
public function deliverAlert(array $alert_data): bool
{
$added_fields = $this->parseUserOptions($this->config['options']);

$discord_title = '#' . $alert_data['uid'] . ' ' . $alert_data['title'];
$discord_msg = $alert_data['msg'];
$color = hexdec(preg_replace('/[^\dA-Fa-f]/', '', self::getColorForState($alert_data['state'])));

// Special handling for the elapsed text in the footer if the elapsed is not set.
$footer_text = $alert_data['elapsed'] ? 'alert took ' . $alert_data['elapsed'] : '';

$data = [
$this->discord_message = [
'embeds' => [
[
'title' => $discord_title,
'color' => $color,
'description' => $discord_msg,
'fields' => $this->createDiscordFields($alert_data),
'title' => $this->getTitle($alert_data),
'color' => $this->getColorOfAlertState($alert_data),
'description' => $this->getDescription($alert_data),
'fields' => $this->getEmbedFields($alert_data),
'footer' => [
'text' => $footer_text,
'text' => $this->getFooter($alert_data),
],
],
],
];
if (! empty($added_fields)) {
$data = array_merge($data, $added_fields);
}

$data = $this->embedGraphs($data);

// remove all remaining HTML tags
$data['embeds'][0]['description'] = strip_tags($data['embeds'][0]['description']);
$this->includeINIFields();
$this->embedGraphs();
$this->stripHTMLTagsFromDescription();

$res = Http::client()->post($this->config['url'], $data);
$res = Http::client()->post($this->config['url'], $this->discord_message);

if ($res->successful()) {
return true;
}

throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $discord_msg, $data);
throw new AlertTransportDeliveryException($alert_data, $res->status(), $res->body(), $alert_data['msg'], $this->discord_message);
}

private function getTitle(array $alert_data): string
{
return '#' . $alert_data['uid'] . ' ' . $alert_data['title'];
}

private function stripHTMLTagsFromDescription(): array
{
$this->discord_message['embeds'][0]['description'] = strip_tags($this->discord_message['embeds'][0]['description']);

return $this->discord_message;
}

private function getColorOfAlertState(array $alert_data): int
{
$hexColor = self::getColorForState($alert_data['state']);
$sanitized = preg_replace('/[^\dA-Fa-f]/', '', $hexColor);

return hexdec($sanitized);
}

private function getDescription(array $alert_data): string
{
return $alert_data['msg'];
}

private function getFooter(array $alert_data): string
{
return $alert_data['elapsed'] ? 'alert took ' . $alert_data['elapsed'] : '';
}

private function includeINIFields(): array
{
$ini_fileds = $this->parseUserOptions($this->config['options']);

if (! empty($ini_fileds)) {
$this->discord_message = array_merge($this->discord_message, $ini_fileds);
}

return $this->discord_message;
}

private function embedGraphs(array $data): array
/**
* Convert an html <img src=""> tag to a json Discord message Embed Image Structure
* https://discord.com/developers/docs/resources/message#embed-object-embed-image-structure
*
* @return array
*/
private function embedGraphs(): array
{
$regex = '#<img class="librenms-graph" src="(.*?)"\s*/>#';
$count = 1;
$data['embeds'][0]['description'] = preg_replace_callback('#<img class="librenms-graph" src="(.*?)" />#', function ($match) use (&$data, &$count) {
$data['embeds'][] = [

$this->discord_message['embeds'][0]['description'] = preg_replace_callback($regex, function ($match) use (&$count) {
$this->discord_message['embeds'][] = [
'image' => [
'url' => $match[1],
],
];

return '[Image ' . ($count++) . ']';
}, $data['embeds'][0]['description']);
}, $this->discord_message['embeds'][0]['description']);

return $data;
return $this->discord_message;
}

public function createDiscordFields(array $alert_data): array
/**
* Converts comma-separated values into an array of name-value pairs.
* https://discord.com/developers/docs/resources/message#embed-object-embed-field-structure
*
* * @param array $alert_data Array containing the values.
* @return array An array of name-value pairs.
*
* @example
* Example with 'hostname,sysDescr' as fields:
* $result will be:
* [
* ['name' => 'Hostname', 'value' => 'server1'],
* ['name' => 'SysDescr', 'value' => 'Linux server description'],
* ]
*/
public function getEmbedFields(array $alert_data): array
{
$result = [];

$fields = explode(',', $this->config['discord-embed-fields'] ?? self::DEFAULT_EMBEDS);
if (empty($this->config['discord-embed-fields'])) {
return $result;
}

$fields = explode(',', $this->config['discord-embed-fields']);

foreach ($fields as $field) {
$field = trim($field);

$result[] = [
'name' => $this->embedFieldTranslations[$field] ?? ucfirst($field),
'value' => $alert_data[$field] ?? 'Error: Invalid Field',
Expand Down Expand Up @@ -133,9 +199,8 @@ public static function configTemplate(): array
[
'title' => 'Fields to embed in the alert',
'name' => 'discord-embed-fields',
'descr' => 'Comma seperated list of fields from the alert to attach to the Discord message',
'descr' => 'Comma seperated list from the alert to embed i.e. hostname,name,timestamp,severity',
'type' => 'text',
'default' => self::DEFAULT_EMBEDS,
],
],
'validation' => [
Expand Down
39 changes: 39 additions & 0 deletions LibreNMS/Interfaces/Discovery/TransceiverDiscovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/*
* TransceiverDiscovery.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2024 Tony Murray
* @author Tony Murray <[email protected]>
*/

namespace LibreNMS\Interfaces\Discovery;

use Illuminate\Support\Collection;

interface TransceiverDiscovery
{
/**
* Discover transceivers.
* Distance is in meters.
*
* @return Collection<\App\Models\Transceiver>
*/
public function discoverTransceivers(): Collection;
}
6 changes: 3 additions & 3 deletions LibreNMS/Interfaces/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ public function cleanup(Device $device): int;
* Make sure to hide transient fields, such as id and date.
* You should always order the data by a non-transient column.
* Some id fields may need to be joined to tie back to non-transient data.
* Module may return false if testing is not supported or required.
* Module may return null if testing is not supported or required.
*
* @return array|false
* @param string $type Type is either discovery or poller
*/
public function dump(Device $device);
public function dump(Device $device, string $type): ?array;
}
6 changes: 5 additions & 1 deletion LibreNMS/Modules/Availability.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
if ($type == 'discovery') {
return null;
}

return [
'availability' => $device->availability()->orderBy('duration')
->get()->map->makeHidden(['availability_id', 'device_id']),
Expand Down
4 changes: 2 additions & 2 deletions LibreNMS/Modules/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return false; // all data here is stored in the devices table and covered by the os module
return null; // all data here is stored in the devices table and covered by the os module
}

/**
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Modules/EntityPhysical.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return [
'entPhysical' => $device->entityPhysical()->orderBy('entPhysicalIndex')
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Modules/Isis.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return [
'isis_adjacencies' => $device->isisAdjacencies()->orderBy('index')
Expand Down
13 changes: 10 additions & 3 deletions LibreNMS/Modules/LegacyModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class LegacyModule implements Module
/** @var array */
private $module_deps = [
'arp-table' => ['ports'],
'bgp-peers' => ['ports', 'vrf'],
'bgp-peers' => ['ports', 'vrf', 'ipv4-addresses', 'ipv6-addresses'],
'cisco-mac-accounting' => ['ports'],
'fdb-table' => ['ports', 'vlans'],
'vlans' => ['ports'],
Expand Down Expand Up @@ -130,12 +130,19 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
if ($type == 'discovery' && ! \LibreNMS\Util\Module::legacyDiscoveryExists($this->name)) {
return null;
}
if ($type == 'poller' && ! \LibreNMS\Util\Module::legacyPollingExists($this->name)) {
return null;
}

$data = [];
$dump_rules = $this->moduleDumpDefinition();
if (empty($dump_rules)) {
return false; // not supported for this legacy module
return null; // not supported for this legacy module
}

foreach ($dump_rules as $table => $info) {
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Modules/Mempools.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return [
'mempools' => $device->mempools()->orderBy('mempool_type')->orderBy('mempool_id')
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Modules/Mpls.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return [
'mpls_lsps' => $device->mplsLsps()->orderBy('vrf_oid')->orderBy('lsp_oid')
Expand Down
6 changes: 5 additions & 1 deletion LibreNMS/Modules/Nac.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
if ($type == 'discovery') {
return null;
}

return [
'ports_nac' => $device->portsNac()->orderBy('ports.ifIndex')->orderBy('mac_address')
->leftJoin('ports', 'ports_nac.port_id', 'ports.port_id')
Expand Down
4 changes: 2 additions & 2 deletions LibreNMS/Modules/Netstats.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
return false; // no database data to dump (may add rrd later)
return null; // no database data to dump (may add rrd later)
}

private function statName(string $oid): string
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Modules/Os.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public function cleanup(Device $device): int
/**
* @inheritDoc
*/
public function dump(Device $device)
public function dump(Device $device, string $type): ?array
{
// get data fresh from the database
return [
Expand Down
Loading

0 comments on commit 9683e9c

Please sign in to comment.