mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls) - Parse coordinates from the location more consistently - Add settings to webui - ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~ - Google Maps, Bing, Mapquest, and OpenStreetMap supported initially. - Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though. - All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate) - Update all (I think) sql queries to handle the new structure - Remove final vestiges of override_sysLocation as a device attribute - Update existing device groups and rules in DB - Tested all APIs with good/bad location, no/bad/good key, and no connection. - Cannot fix advanced queries that use location This blocks #8868 DO NOT DELETE THIS TEXT #### Please note > Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting. - [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/) #### Testers If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926` After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
This commit is contained in:
committed by
Neil Lathwood
parent
eadf27cbcc
commit
3e35ee0e7d
@@ -161,6 +161,12 @@ class Schema
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($tables as $table) {
|
foreach ($tables as $table) {
|
||||||
|
// check for direct relationships
|
||||||
|
if (in_array($table, $relationships[$target])) {
|
||||||
|
d_echo("Direct relationship found $target -> $table\n");
|
||||||
|
return [$table, $target];
|
||||||
|
}
|
||||||
|
|
||||||
$table_relations = $relationships[$table];
|
$table_relations = $relationships[$table];
|
||||||
d_echo("Searching $table: " . json_encode($table_relations) . PHP_EOL);
|
d_echo("Searching $table: " . json_encode($table_relations) . PHP_EOL);
|
||||||
|
|
||||||
|
38
LibreNMS/Interfaces/Geocoder.php
Normal file
38
LibreNMS/Interfaces/Geocoder.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Geocoder.php
|
||||||
|
*
|
||||||
|
* Interface to resolve an address or location string to latitude and longitude coordinates.
|
||||||
|
*
|
||||||
|
* 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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Interfaces;
|
||||||
|
|
||||||
|
interface Geocoder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Try to get the coordinates of a given address.
|
||||||
|
* If unsuccessful, the returned array will be empty
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array ['lat' => 0, 'lng' => 0]
|
||||||
|
*/
|
||||||
|
public function getCoordinates($address);
|
||||||
|
}
|
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
namespace LibreNMS\Util;
|
namespace LibreNMS\Util;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
use LibreNMS\Exceptions\LockException;
|
use LibreNMS\Exceptions\LockException;
|
||||||
use LibreNMS\Interfaces\Lock;
|
use LibreNMS\Interfaces\Lock;
|
||||||
|
|
||||||
@@ -42,10 +43,10 @@ class FileLock implements Lock
|
|||||||
|
|
||||||
private function __construct($lock_name)
|
private function __construct($lock_name)
|
||||||
{
|
{
|
||||||
global $config;
|
$install_dir = Config::get('install_dir');
|
||||||
|
|
||||||
$this->name = $lock_name;
|
$this->name = $lock_name;
|
||||||
$this->file = "$config[install_dir]/.$lock_name.lock";
|
$this->file = "$install_dir/.$lock_name.lock";
|
||||||
$this->handle = fopen($this->file, "w+");
|
$this->handle = fopen($this->file, "w+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
app/ApiClients/BaseApi.php
Normal file
46
app/ApiClients/BaseApi.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BaseApi.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
|
||||||
|
class BaseApi
|
||||||
|
{
|
||||||
|
protected $base_uri;
|
||||||
|
private $client;
|
||||||
|
|
||||||
|
protected function getClient()
|
||||||
|
{
|
||||||
|
if (is_null($this->client)) {
|
||||||
|
$this->client = new Client([
|
||||||
|
'base_uri' => $this->base_uri,
|
||||||
|
'tiemout' => 2,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
}
|
86
app/ApiClients/BingApi.php
Normal file
86
app/ApiClients/BingApi.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BingApi.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\Geocoder;
|
||||||
|
|
||||||
|
class BingApi extends BaseApi implements Geocoder
|
||||||
|
{
|
||||||
|
use GeocodingHelper;
|
||||||
|
|
||||||
|
protected $base_uri = 'http://dev.virtualearth.net';
|
||||||
|
protected $geocoding_uri = '/REST/v1/Locations';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latitude and longitude from geocode response
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function parseLatLng($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'lat' => isset($data['resourceSets'][0]['resources'][0]['point']['coordinates'][0]) ? $data['resourceSets'][0]['resources'][0]['point']['coordinates'][0] : 0,
|
||||||
|
'lng' => isset($data['resourceSets'][0]['resources'][0]['point']['coordinates'][1]) ? $data['resourceSets'][0]['resources'][0]['point']['coordinates'][1] : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Guzzle request option array
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception you may throw an Exception if validation fails
|
||||||
|
*/
|
||||||
|
protected function buildGeocodingOptions($address)
|
||||||
|
{
|
||||||
|
$api_key = Config::get('geoloc.api_key');
|
||||||
|
if (!$api_key) {
|
||||||
|
throw new Exception("Bing API key missing, set geoloc.api_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'query' => [
|
||||||
|
'key' => $api_key,
|
||||||
|
'addressLine' => $address,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the request was a success
|
||||||
|
*
|
||||||
|
* @param \Psr\Http\Message\ResponseInterface $response
|
||||||
|
* @param array $data decoded response data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function checkResponse($response, $data)
|
||||||
|
{
|
||||||
|
return $response->getStatusCode() == 200 && !empty($data['resourceSets'][0]['resources']);
|
||||||
|
}
|
||||||
|
}
|
99
app/ApiClients/GeocodingHelper.php
Normal file
99
app/ApiClients/GeocodingHelper.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* GeocodingHelper.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
trait GeocodingHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* From BaseApi...
|
||||||
|
*
|
||||||
|
* @return \GuzzleHttp\Client
|
||||||
|
*/
|
||||||
|
abstract protected function getClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to get the coordinates of a given address.
|
||||||
|
* If unsuccessful, the returned array will be empty
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array ['lat' => 0, 'lng' => 0]
|
||||||
|
*/
|
||||||
|
public function getCoordinates($address)
|
||||||
|
{
|
||||||
|
if (!Config::get('geoloc.latlng', true)) {
|
||||||
|
Log::debug('Geocoding disabled');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$options = $this->buildGeocodingOptions($address);
|
||||||
|
|
||||||
|
$response = $this->getClient()->get($this->geocoding_uri, $options);
|
||||||
|
$response_data = json_decode($response->getBody(), true);
|
||||||
|
if ($this->checkResponse($response, $response_data)) {
|
||||||
|
return $this->parseLatLng($response_data);
|
||||||
|
} else {
|
||||||
|
Log::error("Geocoding failed.", ['response' => $response_data]);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error("Geocoding failed: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the request was a success
|
||||||
|
*
|
||||||
|
* @param \Psr\Http\Message\ResponseInterface $response
|
||||||
|
* @param array $data decoded response data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function checkResponse($response, $data)
|
||||||
|
{
|
||||||
|
return $response->getStatusCode() == 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latitude and longitude from geocode response
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract protected function parseLatLng($data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Guzzle request option array
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception you may throw an Exception if validation fails
|
||||||
|
*/
|
||||||
|
abstract protected function buildGeocodingOptions($address);
|
||||||
|
}
|
100
app/ApiClients/GoogleMapsApi.php
Normal file
100
app/ApiClients/GoogleMapsApi.php
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* GoogleGeocodeApi.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\Geocoder;
|
||||||
|
|
||||||
|
class GoogleMapsApi extends BaseApi implements Geocoder
|
||||||
|
{
|
||||||
|
use GeocodingHelper;
|
||||||
|
|
||||||
|
protected $base_uri = 'https://maps.googleapis.com';
|
||||||
|
protected $geocoding_uri = '/maps/api/geocode/json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latitude and longitude from geocode response
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function parseLatLng($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'lat' => isset($data['results'][0]['geometry']['location']['lat']) ? $data['results'][0]['geometry']['location']['lat'] : 0,
|
||||||
|
'lng' => isset($data['results'][0]['geometry']['location']['lng']) ? $data['results'][0]['geometry']['location']['lng'] : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get messages from response.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function parseMessages($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'error' => isset($data['error_message']) ? $data['error_message'] : '',
|
||||||
|
'response' => $data,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Guzzle request option array
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception you may throw an Exception if validation fails
|
||||||
|
*/
|
||||||
|
protected function buildGeocodingOptions($address)
|
||||||
|
{
|
||||||
|
$api_key = Config::get('geoloc.api_key');
|
||||||
|
if (!$api_key) {
|
||||||
|
throw new Exception('Google Maps API key missing, set geoloc.api_key');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'query' => [
|
||||||
|
'key' => $api_key,
|
||||||
|
'address' => $address,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the request was a success
|
||||||
|
*
|
||||||
|
* @param \Psr\Http\Message\ResponseInterface $response
|
||||||
|
* @param array $data decoded response data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function checkResponse($response, $data)
|
||||||
|
{
|
||||||
|
return $response->getStatusCode() == 200 && $data['status'] == 'OK';
|
||||||
|
}
|
||||||
|
}
|
87
app/ApiClients/MapquestApi.php
Normal file
87
app/ApiClients/MapquestApi.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* MapquestGeocodeApi.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\Geocoder;
|
||||||
|
|
||||||
|
class MapquestApi extends BaseApi implements Geocoder
|
||||||
|
{
|
||||||
|
use GeocodingHelper;
|
||||||
|
|
||||||
|
protected $base_uri = 'https://open.mapquestapi.com';
|
||||||
|
protected $geocoding_uri = '/geocoding/v1/address';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latitude and longitude from geocode response
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function parseLatLng($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'lat' => isset($data['results'][0]['locations'][0]['latLng']['lat']) ? $data['results'][0]['locations'][0]['latLng']['lat'] : 0,
|
||||||
|
'lng' => isset($data['results'][0]['locations'][0]['latLng']['lng']) ? $data['results'][0]['locations'][0]['latLng']['lng'] : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Guzzle request option array
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception you may throw an Exception if validation fails
|
||||||
|
*/
|
||||||
|
protected function buildGeocodingOptions($address)
|
||||||
|
{
|
||||||
|
$api_key = Config::get('geoloc.api_key');
|
||||||
|
if (!$api_key) {
|
||||||
|
throw new Exception("MapQuest API key missing, set geoloc.api_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'query' => [
|
||||||
|
'key' => $api_key,
|
||||||
|
'location' => $address,
|
||||||
|
'thumbMaps' => 'false',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the request was a success
|
||||||
|
*
|
||||||
|
* @param \Psr\Http\Message\ResponseInterface $response
|
||||||
|
* @param array $data decoded response data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function checkResponse($response, $data)
|
||||||
|
{
|
||||||
|
return $response->getStatusCode() == 200 && $data['info']['statuscode'] == 0;
|
||||||
|
}
|
||||||
|
}
|
72
app/ApiClients/NominatimApi.php
Normal file
72
app/ApiClients/NominatimApi.php
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* NominatimApi.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\ApiClients;
|
||||||
|
|
||||||
|
use LibreNMS\Interfaces\Geocoder;
|
||||||
|
|
||||||
|
class NominatimApi extends BaseApi implements Geocoder
|
||||||
|
{
|
||||||
|
use GeocodingHelper;
|
||||||
|
|
||||||
|
protected $base_uri = 'http://nominatim.openstreetmap.org';
|
||||||
|
protected $geocoding_uri = '/search';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latitude and longitude from geocode response
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function parseLatLng($data)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'lat' => isset($data[0]['lat']) ? $data[0]['lat'] : 0,
|
||||||
|
'lng' => isset($data[0]['lon']) ? $data[0]['lon'] : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Guzzle request option array
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception you may throw an Exception if validation fails
|
||||||
|
*/
|
||||||
|
protected function buildGeocodingOptions($address)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'query' => [
|
||||||
|
'q' => $address,
|
||||||
|
'format' => 'json',
|
||||||
|
'limit' => 1,
|
||||||
|
],
|
||||||
|
'headers' => [
|
||||||
|
'User-Agent' => 'LibreNMS',
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -32,6 +32,7 @@ use App\Models\CefSwitching;
|
|||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
use App\Models\DeviceGroup;
|
use App\Models\DeviceGroup;
|
||||||
|
use App\Models\Location;
|
||||||
use App\Models\Notification;
|
use App\Models\Notification;
|
||||||
use App\Models\OspfInstance;
|
use App\Models\OspfInstance;
|
||||||
use App\Models\Package;
|
use App\Models\Package;
|
||||||
@@ -73,7 +74,7 @@ class MenuComposer
|
|||||||
$vars['device_types'] = Device::hasAccess($user)->select('type')->distinct()->get()->pluck('type')->filter();
|
$vars['device_types'] = Device::hasAccess($user)->select('type')->distinct()->get()->pluck('type')->filter();
|
||||||
|
|
||||||
if (Config::get('show_locations') && Config::get('show_locations_dropdown')) {
|
if (Config::get('show_locations') && Config::get('show_locations_dropdown')) {
|
||||||
$vars['locations'] = Device::hasAccess($user)->select('location')->distinct()->get()->pluck('location')->filter();
|
$vars['locations'] = Location::hasAccess($user)->select('location')->get()->map->display()->filter();
|
||||||
} else {
|
} else {
|
||||||
$vars['locations'] = [];
|
$vars['locations'] = [];
|
||||||
}
|
}
|
||||||
|
@@ -455,6 +455,11 @@ class Device extends BaseModel
|
|||||||
return $this->belongsToMany('App\Models\DeviceGroup', 'device_group_device', 'device_id', 'device_group_id');
|
return $this->belongsToMany('App\Models\DeviceGroup', 'device_group_device', 'device_id', 'device_group_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function location()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Location', 'location_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
public function ospfInstances()
|
public function ospfInstances()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\OspfInstance', 'device_id');
|
return $this->hasMany('App\Models\OspfInstance', 'device_id');
|
||||||
|
150
app/Models/Location.php
Normal file
150
app/Models/Location.php
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Location.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Location extends Model
|
||||||
|
{
|
||||||
|
public $fillable = ['location', 'lat', 'lng'];
|
||||||
|
const CREATED_AT = null;
|
||||||
|
const UPDATED_AT = 'timestamp';
|
||||||
|
|
||||||
|
private $location_regex = '/\[\s*(?<lat>[-+]?(?:[1-8]?\d(?:\.\d+)?|90(?:\.0+)?))\s*,\s*(?<lng>[-+]?(?:180(?:\.0+)?|(?:(?:1[0-7]\d)|(?:[1-9]?\d))(?:\.\d+)?))\s*\]/';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up listeners for this Model
|
||||||
|
*/
|
||||||
|
public static function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::creating(function (Location $location) {
|
||||||
|
// parse coordinates for new locations
|
||||||
|
$location->lookupCoordinates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Helper Functions ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this location has resolved latitude and longitude.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasCoordinates()
|
||||||
|
{
|
||||||
|
return !(is_null($this->lat) || is_null($this->lng));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the coordinates are valid
|
||||||
|
* Even though 0,0 is a valid coordinate, we consider it invalid for ease
|
||||||
|
*/
|
||||||
|
public function coordinatesValid()
|
||||||
|
{
|
||||||
|
return $this->lat && $this->lng &&
|
||||||
|
abs($this->lat) <= 90 && abs($this->lng) <= 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to parse coordinates then
|
||||||
|
* call geocoding API to resolve latitude and longitude.
|
||||||
|
*/
|
||||||
|
public function lookupCoordinates()
|
||||||
|
{
|
||||||
|
if (!$this->hasCoordinates() && $this->location) {
|
||||||
|
$this->parseCoordinates();
|
||||||
|
|
||||||
|
if (!$this->hasCoordinates() &&
|
||||||
|
\LibreNMS\Config::get('geoloc.latlng', true) &&
|
||||||
|
$this->timestamp && $this->timestamp->diffInDays() > 2
|
||||||
|
) {
|
||||||
|
$this->fetchCoordinates();
|
||||||
|
$this->updateTimestamps();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove encoded GPS for nicer display
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function display()
|
||||||
|
{
|
||||||
|
return trim(preg_replace($this->location_regex, '', $this->location)) ?: $this->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseCoordinates()
|
||||||
|
{
|
||||||
|
if (preg_match($this->location_regex, $this->location, $parsed)) {
|
||||||
|
$this->fill($parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fetchCoordinates()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
/** @var \LibreNMS\Interfaces\Geocoder $api */
|
||||||
|
$api = app(\LibreNMS\Interfaces\Geocoder::class);
|
||||||
|
$this->fill($api->getCoordinates($this->location));
|
||||||
|
} catch (BindingResolutionException $e) {
|
||||||
|
// could not resolve geocoder, Laravel isn't booted. Fail silently.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Query scopes ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param User $user
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function scopeHasAccess($query, $user)
|
||||||
|
{
|
||||||
|
if ($user->hasGlobalRead()) {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = Device::hasAccess($user)
|
||||||
|
->distinct()
|
||||||
|
->whereNotNull('location_id')
|
||||||
|
->pluck('location_id');
|
||||||
|
|
||||||
|
return $query->whereIn('id', $ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Define Relationships ----
|
||||||
|
|
||||||
|
public function devices()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Device', 'location_id');
|
||||||
|
}
|
||||||
|
}
|
@@ -73,7 +73,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
//
|
$this->registerGeocoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function configureMorphAliases()
|
private function configureMorphAliases()
|
||||||
@@ -83,4 +83,28 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
'sensor' => \App\Models\Sensor::class,
|
'sensor' => \App\Models\Sensor::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function registerGeocoder()
|
||||||
|
{
|
||||||
|
$this->app->alias(\LibreNMS\Interfaces\Geocoder::class, 'geocoder');
|
||||||
|
$this->app->bind(\LibreNMS\Interfaces\Geocoder::class, function ($app) {
|
||||||
|
$engine = Config::get('geoloc.engine');
|
||||||
|
|
||||||
|
switch ($engine) {
|
||||||
|
case 'mapquest':
|
||||||
|
Log::debug('MapQuest geocode engine');
|
||||||
|
return $app->make(\App\ApiClients\MapquestApi::class);
|
||||||
|
case 'bing':
|
||||||
|
Log::debug('Bing geocode engine');
|
||||||
|
return $app->make(\App\ApiClients\BingApi::class);
|
||||||
|
case 'openstreetmap':
|
||||||
|
Log::debug('OpenStreetMap geocode engine');
|
||||||
|
return $app->make(\App\ApiClients\NominatimApi::class);
|
||||||
|
default:
|
||||||
|
case 'google':
|
||||||
|
Log::debug('Google Maps geocode engine');
|
||||||
|
return $app->make(\App\ApiClients\GoogleMapsApi::class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -313,14 +313,14 @@ function list_devices()
|
|||||||
}
|
}
|
||||||
|
|
||||||
$select = " d.*, GROUP_CONCAT(dd.device_id) AS dependency_parent_id, GROUP_CONCAT(dd.hostname) AS dependency_parent_hostname, `lat`, `lng` ";
|
$select = " d.*, GROUP_CONCAT(dd.device_id) AS dependency_parent_id, GROUP_CONCAT(dd.hostname) AS dependency_parent_hostname, `lat`, `lng` ";
|
||||||
$join = " LEFT JOIN `device_relationships` AS dr ON dr.`child_device_id` = d.`device_id` LEFT JOIN `devices` AS dd ON dr.`parent_device_id` = dd.`device_id` LEFT JOIN `locations` ON `locations`.`location` = `d`.`location`";
|
$join = " LEFT JOIN `device_relationships` AS dr ON dr.`child_device_id` = d.`device_id` LEFT JOIN `devices` AS dd ON dr.`parent_device_id` = dd.`device_id` LEFT JOIN `locations` ON `locations`.`id` = `d`.`location_id`";
|
||||||
|
|
||||||
if ($type == 'all' || empty($type)) {
|
if ($type == 'all' || empty($type)) {
|
||||||
$sql = '1';
|
$sql = '1';
|
||||||
} elseif ($type == 'active') {
|
} elseif ($type == 'active') {
|
||||||
$sql = "`d`.`ignore`='0' AND `d`.`disabled`='0'";
|
$sql = "`d`.`ignore`='0' AND `d`.`disabled`='0'";
|
||||||
} elseif ($type == 'location') {
|
} elseif ($type == 'location') {
|
||||||
$sql = "`d`.`location` LIKE '%".$query."%'";
|
$sql = "`locations`.`location` LIKE '%".$query."%'";
|
||||||
} elseif ($type == 'ignored') {
|
} elseif ($type == 'ignored') {
|
||||||
$sql = "`d`.`ignore`='1' AND `d`.`disabled`='0'";
|
$sql = "`d`.`ignore`='1' AND `d`.`disabled`='0'";
|
||||||
} elseif ($type == 'up') {
|
} elseif ($type == 'up') {
|
||||||
@@ -1296,7 +1296,7 @@ function list_oxidized()
|
|||||||
$params = array($hostname);
|
$params = array($hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (dbFetchRows("SELECT hostname,sysname,sysDescr,hardware,os,location,ip AS ip FROM `devices` LEFT JOIN devices_attribs AS `DA` ON devices.device_id = DA.device_id AND `DA`.attrib_type='override_Oxidized_disable' WHERE `disabled`='0' AND `ignore` = 0 AND (DA.attrib_value = 'false' OR DA.attrib_value IS NULL) AND (`type` NOT IN ($device_types) AND `os` NOT IN ($device_os)) $sql", $params) as $device) {
|
foreach (dbFetchRows("SELECT hostname,sysname,sysDescr,hardware,os,locations.location,ip AS ip FROM `devices` LEFT JOIN devices_attribs AS `DA` ON devices.device_id = DA.device_id LEFT JOIN locations ON devices.location_id = locations.id AND `DA`.attrib_type='override_Oxidized_disable' WHERE `disabled`='0' AND `ignore` = 0 AND (DA.attrib_value = 'false' OR DA.attrib_value IS NULL) AND (`type` NOT IN ($device_types) AND `os` NOT IN ($device_os)) $sql", $params) as $device) {
|
||||||
// Convert from packed value to human value
|
// Convert from packed value to human value
|
||||||
$device['ip'] = inet6_ntop($device['ip']);
|
$device['ip'] = inet6_ntop($device['ip']);
|
||||||
|
|
||||||
|
@@ -38,14 +38,15 @@ $temp_output .= "
|
|||||||
";
|
";
|
||||||
|
|
||||||
$locations = array();
|
$locations = array();
|
||||||
foreach (getlocations() as $location) {
|
foreach (getlocations() as $location_row) {
|
||||||
$location = mres($location);
|
$location = $location_row['location'];
|
||||||
|
$location_id = $location_row['id'];
|
||||||
$devices = array();
|
$devices = array();
|
||||||
$devices_down = array();
|
$devices_down = array();
|
||||||
$devices_up = array();
|
$devices_up = array();
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$down = 0;
|
$down = 0;
|
||||||
foreach (dbFetchRows("SELECT devices.device_id,devices.hostname,devices.status FROM devices LEFT JOIN devices_attribs ON devices.device_id = devices_attribs.device_id WHERE ( devices.location = ? || ( devices_attribs.attrib_type = 'override_sysLocation_string' && devices_attribs.attrib_value = ? ) ) && devices.disabled = 0 && devices.ignore = 0 GROUP BY devices.hostname", array($location,$location)) as $device) {
|
foreach (dbFetchRows("SELECT `device_id`, `hostname`, `status` FROM `devices` WHERE `location_id` = ? && `disabled` = 0 && `ignore` = 0 GROUP BY `hostname`", [$location_id]) as $device) {
|
||||||
if ($config['frontpage_globe']['markers'] == 'devices' || empty($config['frontpage_globe']['markers'])) {
|
if ($config['frontpage_globe']['markers'] == 'devices' || empty($config['frontpage_globe']['markers'])) {
|
||||||
$devices[] = $device['hostname'];
|
$devices[] = $device['hostname'];
|
||||||
$count++;
|
$count++;
|
||||||
@@ -67,7 +68,7 @@ foreach (getlocations() as $location) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pdown = ($down / $count)*100;
|
$pdown = $count ? ($down / $count)*100 : 0;
|
||||||
if ($config['frontpage_globe']['markers'] == 'devices' || empty($config['frontpage_globe']['markers'])) {
|
if ($config['frontpage_globe']['markers'] == 'devices' || empty($config['frontpage_globe']['markers'])) {
|
||||||
$devices_down = array_merge(array(count($devices_up). " Devices OK"), $devices_down);
|
$devices_down = array_merge(array(count($devices_up). " Devices OK"), $devices_down);
|
||||||
} elseif ($config['frontpage_globe']['markers'] == 'ports') {
|
} elseif ($config['frontpage_globe']['markers'] == 'ports') {
|
||||||
|
@@ -173,18 +173,18 @@ var greenMarker = L.AwesomeMarkers.icon({
|
|||||||
// Checking user permissions
|
// Checking user permissions
|
||||||
if (LegacyAuth::user()->hasGlobalRead()) {
|
if (LegacyAuth::user()->hasGlobalRead()) {
|
||||||
// Admin or global read-only - show all devices
|
// Admin or global read-only - show all devices
|
||||||
$sql = "SELECT DISTINCT(`device_id`),`devices`.`location`,`sysName`,`hostname`,`os`,`status`,`lat`,`lng` FROM `devices`
|
$sql = "SELECT DISTINCT(`device_id`),`location`,`sysName`,`hostname`,`os`,`status`,`lat`,`lng` FROM `devices`
|
||||||
LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location`
|
LEFT JOIN `locations` ON `devices`.`location_id`=`locations`.`id`
|
||||||
WHERE `disabled`=0 AND `ignore`=0 AND ((`lat` != '' AND `lng` != '') OR (`devices`.`location` REGEXP '\[[0-9\.\, ]+\]'))
|
WHERE `disabled`=0 AND `ignore`=0 AND ((`lat` != '' AND `lng` != '') OR (`location` REGEXP '\[[0-9\.\, ]+\]'))
|
||||||
AND `status` IN " . dbGenPlaceholders(count($status_select)) .
|
AND `status` IN " . dbGenPlaceholders(count($status_select)) .
|
||||||
" ORDER BY `status` ASC, `hostname`";
|
" ORDER BY `status` ASC, `hostname`";
|
||||||
$param = $status_select;
|
$param = $status_select;
|
||||||
} else {
|
} else {
|
||||||
// Normal user - grab devices that user has permissions to
|
// Normal user - grab devices that user has permissions to
|
||||||
$sql = "SELECT DISTINCT(`devices`.`device_id`) as `device_id`,`devices`.`location`,`sysName`,`hostname`,`os`,`status`,`lat`,`lng`
|
$sql = "SELECT DISTINCT(`devices`.`device_id`) as `device_id`,`location`,`sysName`,`hostname`,`os`,`status`,`lat`,`lng`
|
||||||
FROM `devices_perms`, `devices`
|
FROM `devices_perms`, `devices`
|
||||||
LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location`
|
LEFT JOIN `locations` ON `devices`.location_id=`locations`.`id`
|
||||||
WHERE `disabled`=0 AND `ignore`=0 AND ((`lat` != '' AND `lng` != '') OR (`devices`.`location` REGEXP '\[[0-9\.\, ]+\]'))
|
WHERE `disabled`=0 AND `ignore`=0 AND ((`lat` != '' AND `lng` != '') OR (`location` REGEXP '\[[0-9\.\, ]+\]'))
|
||||||
AND `devices`.`device_id` = `devices_perms`.`device_id`
|
AND `devices`.`device_id` = `devices_perms`.`device_id`
|
||||||
AND `devices_perms`.`user_id` = ? AND `status` IN " . dbGenPlaceholders(count($status_select)) .
|
AND `devices_perms`.`user_id` = ? AND `status` IN " . dbGenPlaceholders(count($status_select)) .
|
||||||
" ORDER BY `status` ASC, `hostname`";
|
" ORDER BY `status` ASC, `hostname`";
|
||||||
|
@@ -100,28 +100,19 @@ if ($device['sysContact']) {
|
|||||||
</tr>';
|
</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($device['location']) {
|
if ($device['location_id']) {
|
||||||
echo '<tr>
|
$location = \App\Models\Location::find($device['location_id']);
|
||||||
<td>Location</td>
|
|
||||||
<td>'.$device['location'].'</td>
|
|
||||||
</tr>';
|
|
||||||
if (get_dev_attrib($device, 'override_sysLocation_bool') && !empty($device['real_location'])) {
|
|
||||||
echo '<tr>
|
echo '<tr>
|
||||||
<td>SNMP Location</td>
|
<td>Location</td>
|
||||||
<td>'.$device['real_location'].'</td>
|
<td>' . $location->location . '</td>
|
||||||
</tr>';
|
</tr>';
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$loc = parse_location($device['location']);
|
if ($location->coordinatesValid()) {
|
||||||
if (!is_array($loc)) {
|
echo '<tr>
|
||||||
$loc = dbFetchRow("SELECT `lat`,`lng` FROM `locations` WHERE `location`=? LIMIT 1", array($device['location']));
|
|
||||||
}
|
|
||||||
if (is_array($loc)) {
|
|
||||||
echo '<tr>
|
|
||||||
<td>Lat / Lng</td>
|
<td>Lat / Lng</td>
|
||||||
<td>['.$loc['lat'].','.$loc['lng'].'] <div class="pull-right"><a href="https://maps.google.com/?q='.$loc['lat'].'+'.$loc['lng'].'" target="_blank" class="btn btn-success btn-xs" role="button"><i class="fa fa-map-marker" style="color:white" aria-hidden="true"></i> Map</button></div></a></td>
|
<td>[' . $location->lat . ',' . $location->lng . '] <div class="pull-right"><a href="https://maps.google.com/?q=' . $location->lat . '+' . $location->lng . '" target="_blank" class="btn btn-success btn-xs" role="button"><i class="fa fa-map-marker" style="color:white" aria-hidden="true"></i> Map</button></div></a></td>
|
||||||
</tr>';
|
</tr>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
|
@@ -24,7 +24,7 @@ $transport = $vars['transport'] ?: null;
|
|||||||
$transport_id = $vars['transport_id'] ?: null;
|
$transport_id = $vars['transport_id'] ?: null;
|
||||||
|
|
||||||
require_once $config['install_dir'].'/includes/alerts.inc.php';
|
require_once $config['install_dir'].'/includes/alerts.inc.php';
|
||||||
$tmp = array(dbFetchRow('select device_id,hostname,sysDescr,version,hardware,location from devices order by device_id asc limit 1'));
|
$tmp = array(dbFetchRow('select device_id,hostname,sysDescr,version,hardware,location_id from devices order by device_id asc limit 1'));
|
||||||
$tmp['contacts'] = GetContacts($tmp);
|
$tmp['contacts'] = GetContacts($tmp);
|
||||||
$obj = array(
|
$obj = array(
|
||||||
"hostname" => $tmp[0]['hostname'],
|
"hostname" => $tmp[0]['hostname'],
|
||||||
|
@@ -880,27 +880,12 @@ function devclass($device)
|
|||||||
|
|
||||||
function getlocations()
|
function getlocations()
|
||||||
{
|
{
|
||||||
$locations = array();
|
|
||||||
|
|
||||||
// Fetch regular locations
|
|
||||||
if (LegacyAuth::user()->hasGlobalRead()) {
|
if (LegacyAuth::user()->hasGlobalRead()) {
|
||||||
$rows = dbFetchRows('SELECT location FROM devices AS D GROUP BY location ORDER BY location');
|
return dbFetchRows('SELECT id, location FROM locations ORDER BY location');
|
||||||
} else {
|
|
||||||
$rows = dbFetchRows('SELECT location FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? GROUP BY location ORDER BY location', array(LegacyAuth::id()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
return dbFetchRows('SELECT id, L.location FROM devices AS D, locations AS L, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND D.location_id = L.id ORDER BY location', [LegacyAuth::id()]);
|
||||||
// Only add it as a location if it wasn't overridden (and not already there)
|
}
|
||||||
if ($row['location'] != '') {
|
|
||||||
if (!in_array($row['location'], $locations)) {
|
|
||||||
$locations[] = $row['location'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort($locations);
|
|
||||||
return $locations;
|
|
||||||
}//end getlocations()
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
foreach (dbFetchRows('SELECT * FROM `devices` WHERE `location` = ?', array($vars['id'])) as $device) {
|
foreach (dbFetchRows('SELECT * FROM `devices`,`locations` WHERE location_id = ? && devices.location_id = locations.id', [$vars['id']]) as $device) {
|
||||||
if ($auth || device_permitted($device_id)) {
|
if ($auth || device_permitted($device_id)) {
|
||||||
$devices[] = $device;
|
$devices[] = $device;
|
||||||
$title = $vars['id'];
|
$title = $device['location'];
|
||||||
$auth = true;
|
$auth = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -189,9 +189,10 @@ if (Auth::user()->hasGlobalAdmin()) {
|
|||||||
<li class="dropdown-submenu">
|
<li class="dropdown-submenu">
|
||||||
<a href="#"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> Geo Locations</a>
|
<a href="#"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> Geo Locations</a>
|
||||||
<ul class="dropdown-menu scrollable-menu">
|
<ul class="dropdown-menu scrollable-menu">
|
||||||
|
<li><a href="locations"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> All Locations</a></li>
|
||||||
');
|
');
|
||||||
foreach ($locations as $location) {
|
foreach ($locations as $location) {
|
||||||
echo(' <li><a href="devices/location=' . urlencode($location) . '/"><i class="fa fa-building fa-fw fa-lg" aria-hidden="true"></i> ' . $location . ' </a></li>');
|
echo(' <li><a href="devices/location=' . $location['id'] . '/"><i class="fa fa-building fa-fw fa-lg" aria-hidden="true"></i> ' . htmlentities($location['location']) . ' </a></li>');
|
||||||
}
|
}
|
||||||
echo('
|
echo('
|
||||||
</ul>
|
</ul>
|
||||||
|
@@ -117,7 +117,7 @@ if ($rowCount != -1) {
|
|||||||
$sql .= " LIMIT $limit_low,$limit_high";
|
$sql .= " LIMIT $limit_low,$limit_high";
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT `alerts`.*, `devices`.`hostname`, `devices`.`sysName`, `devices`.`hardware`, `devices`.`location`, `alert_rules`.`rule`, `alert_rules`.`name`, `alert_rules`.`severity` $sql";
|
$sql = "SELECT `alerts`.*, `devices`.`hostname`, `devices`.`sysName`, `devices`.`hardware`, `alert_rules`.`rule`, `alert_rules`.`name`, `alert_rules`.`severity` $sql";
|
||||||
|
|
||||||
$rulei = 0;
|
$rulei = 0;
|
||||||
$format = $vars['format'];
|
$format = $vars['format'];
|
||||||
|
@@ -18,7 +18,7 @@ use LibreNMS\Authentication\LegacyAuth;
|
|||||||
$where = 1;
|
$where = 1;
|
||||||
$param = array();
|
$param = array();
|
||||||
|
|
||||||
$sql = ' FROM `devices`';
|
$sql = ' FROM `devices` LEFT JOIN locations ON devices.location_id = locations.id';
|
||||||
|
|
||||||
if (!LegacyAuth::user()->hasGlobalRead()) {
|
if (!LegacyAuth::user()->hasGlobalRead()) {
|
||||||
$sql .= ' LEFT JOIN `devices_perms` AS `DP` ON `devices`.`device_id` = `DP`.`device_id`';
|
$sql .= ' LEFT JOIN `devices_perms` AS `DP` ON `devices`.`device_id` = `DP`.`device_id`';
|
||||||
@@ -26,10 +26,6 @@ if (!LegacyAuth::user()->hasGlobalRead()) {
|
|||||||
$param[] = LegacyAuth::id();
|
$param[] = LegacyAuth::id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($vars['location'])) {
|
|
||||||
$sql .= " LEFT JOIN `devices_attribs` AS `DB` ON `DB`.`device_id`=`devices`.`device_id` AND `DB`.`attrib_type`='override_sysLocation_bool' AND `DB`.`attrib_value`='1' LEFT JOIN `devices_attribs` AS `DA` ON `devices`.`device_id`=`DA`.`device_id`";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($vars['group']) && is_numeric($vars['group'])) {
|
if (!empty($vars['group']) && is_numeric($vars['group'])) {
|
||||||
$sql .= " LEFT JOIN `device_group_device` AS `DG` ON `DG`.`device_id`=`devices`.`device_id`";
|
$sql .= " LEFT JOIN `device_group_device` AS `DG` ON `DG`.`device_id`=`devices`.`device_id`";
|
||||||
$where .= " AND `DG`.`device_group_id`=?";
|
$where .= " AND `DG`.`device_group_id`=?";
|
||||||
@@ -97,7 +93,8 @@ if (!empty($vars['location']) && $vars['location'] == 'Unset') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($vars['location'])) {
|
if (!empty($vars['location'])) {
|
||||||
$sql .= " AND `location` = ?";
|
$sql .= " AND (`location` = ? OR `location_id` = ?)";
|
||||||
|
$param[] = $vars['location'];
|
||||||
$param[] = $vars['location'];
|
$param[] = $vars['location'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +117,7 @@ if ($rowCount != -1) {
|
|||||||
$sql .= " LIMIT $limit_low,$limit_high";
|
$sql .= " LIMIT $limit_low,$limit_high";
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT DISTINCT(`devices`.`device_id`),`devices`.* $sql";
|
$sql = "SELECT DISTINCT(`devices`.`device_id`),`devices`.*,locations.location $sql";
|
||||||
|
|
||||||
if (!isset($vars['format'])) {
|
if (!isset($vars['format'])) {
|
||||||
$vars['format'] = 'list_detail';
|
$vars['format'] = 'list_detail';
|
||||||
|
@@ -46,7 +46,7 @@ if (!empty($vars['hostname'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($vars['location'])) {
|
if (!empty($vars['location'])) {
|
||||||
$where .= " AND `D`.`location` = ?";
|
$where .= " AND `D`.`location_id` = ?";
|
||||||
$param[] = $vars['location'];
|
$param[] = $vars['location'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,10 +36,11 @@ if (isset($config['branding']) && is_array($config['branding'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$where = '';
|
||||||
|
$param = [];
|
||||||
if (is_numeric($_GET['device']) && isset($_GET['device'])) {
|
if (is_numeric($_GET['device']) && isset($_GET['device'])) {
|
||||||
$where = 'WHERE device_id = '.mres($_GET['device']);
|
$where = '&& device_id = ?';
|
||||||
} else {
|
$param[] = $_GET['device'];
|
||||||
$where = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME this shit probably needs tidied up.
|
// FIXME this shit probably needs tidied up.
|
||||||
@@ -57,7 +58,7 @@ if (isset($_GET['format']) && preg_match("/^[a-z]*$/", $_GET['format'])) {
|
|||||||
} else {
|
} else {
|
||||||
$loc_count = 1;
|
$loc_count = 1;
|
||||||
|
|
||||||
foreach (dbFetch("SELECT * from devices ".$where) as $device) {
|
foreach (dbFetch("SELECT *, locations.location from devices,locations WHERE devices.location_id = locations.id ".$where, $param) as $device) {
|
||||||
if ($device) {
|
if ($device) {
|
||||||
$links = dbFetch("SELECT * from ports AS I, links AS L WHERE I.device_id = ? AND L.local_port_id = I.port_id ORDER BY L.remote_hostname", array($device['device_id']));
|
$links = dbFetch("SELECT * from ports AS I, links AS L WHERE I.device_id = ? AND L.local_port_id = I.port_id ORDER BY L.remote_hostname", array($device['device_id']));
|
||||||
if (count($links)) {
|
if (count($links)) {
|
||||||
|
@@ -1,70 +1,57 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
|
use App\Models\Location;
|
||||||
use LibreNMS\Authentication\LegacyAuth;
|
use LibreNMS\Authentication\LegacyAuth;
|
||||||
|
|
||||||
|
$device_model = Device::find($device['device_id']);
|
||||||
|
|
||||||
if ($_POST['editing']) {
|
if ($_POST['editing']) {
|
||||||
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
||||||
$updated = 0;
|
|
||||||
|
|
||||||
if (isset($_POST['parent_id'])) {
|
if (isset($_POST['parent_id'])) {
|
||||||
$parents = array_diff((array)$_POST['parent_id'], ['0']);
|
$parents = array_diff((array)$_POST['parent_id'], ['0']);
|
||||||
// TODO avoid loops!
|
// TODO avoid loops!
|
||||||
Device::find($device['device_id'])->parents()->sync($parents);
|
$device_model->parents()->sync($parents);
|
||||||
}
|
}
|
||||||
|
|
||||||
$override_sysLocation_bool = mres($_POST['override_sysLocation']);
|
$override_sysLocation = (int)isset($_POST['override_sysLocation']);
|
||||||
if (isset($_POST['sysLocation'])) {
|
$override_sysLocation_string = isset($_POST['sysLocation']) ? $_POST['sysLocation'] : null;
|
||||||
$override_sysLocation_string = $_POST['sysLocation'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($device['override_sysLocation'] != $override_sysLocation_bool || $device['location'] != $override_sysLocation_string) {
|
if ($override_sysLocation) {
|
||||||
$updated = 1;
|
if ($override_sysLocation_string) {
|
||||||
}
|
$location = Location::firstOrCreate(['location' => $override_sysLocation_string]);
|
||||||
|
$device_model->location()->associate($location);
|
||||||
if ($override_sysLocation_bool) {
|
} else {
|
||||||
$override_sysLocation = 1;
|
$device_model->location()->dissociate();
|
||||||
} else {
|
|
||||||
$override_sysLocation = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbUpdate(array('override_sysLocation'=>$override_sysLocation), 'devices', '`device_id`=?', array($device['device_id']));
|
|
||||||
|
|
||||||
if (isset($override_sysLocation_string)) {
|
|
||||||
dbUpdate(array('location'=>$override_sysLocation_string), 'devices', '`device_id`=?', array($device['device_id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($device['type'] != $vars['type']) {
|
|
||||||
$param['type'] = $vars['type'];
|
|
||||||
$update_type = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#FIXME needs more sanity checking! and better feedback
|
|
||||||
|
|
||||||
$param['purpose'] = $vars['descr'];
|
|
||||||
$param['ignore'] = set_numeric($vars['ignore']);
|
|
||||||
$param['disabled'] = set_numeric($vars['disabled']);
|
|
||||||
|
|
||||||
$rows_updated = dbUpdate($param, 'devices', '`device_id` = ?', array($device['device_id']));
|
|
||||||
|
|
||||||
if ($rows_updated > 0 || $updated) {
|
|
||||||
if ($update_type === true) {
|
|
||||||
set_dev_attrib($device, 'override_device_type', true);
|
|
||||||
}
|
}
|
||||||
$update_message = "Device record updated.";
|
} elseif ($device_model->override_sysLocation) {
|
||||||
$updated = 1;
|
// no longer overridden, clear location
|
||||||
$device = dbFetchRow("SELECT * FROM `devices` WHERE `device_id` = ?", array($device['device_id']));
|
$device_model->location()->dissociate();
|
||||||
} elseif ($rows_updated == 0) {
|
|
||||||
$update_message = "Device record unchanged. No update necessary.";
|
|
||||||
$updated = -1;
|
|
||||||
} else {
|
|
||||||
$update_message = "Device record update error.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$device_model->override_sysLocation = $override_sysLocation;
|
||||||
|
$device_model->purpose = $_POST['descr'];
|
||||||
|
$device_model->ignore = (int)isset($_POST['ignore']);
|
||||||
|
$device_model->disabled = (int)isset($_POST['disabled']);
|
||||||
|
$device_model->type = $_POST['type'];
|
||||||
|
|
||||||
|
if ($device_model->isDirty('type')) {
|
||||||
|
set_dev_attrib($device, 'override_device_type', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($device_model->isDirty()) {
|
||||||
|
if ($device_model->save()) {
|
||||||
|
Toastr::success(__('Device record updated'));
|
||||||
|
} else {
|
||||||
|
Toastr::error(__('Device record update error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($_POST['hostname']) && $_POST['hostname'] !== '' && $_POST['hostname'] !== $device['hostname']) {
|
if (isset($_POST['hostname']) && $_POST['hostname'] !== '' && $_POST['hostname'] !== $device['hostname']) {
|
||||||
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
||||||
$result = renamehost($device['device_id'], $_POST['hostname'], 'webui');
|
$result = renamehost($device['device_id'], $_POST['hostname'], 'webui');
|
||||||
if ($result == "") {
|
if ($result == "") {
|
||||||
print_message("Hostname updated from {$device['hostname']} to {$_POST['hostname']}");
|
Toastr::success("Hostname updated from {$device['hostname']} to {$_POST['hostname']}");
|
||||||
echo '
|
echo '
|
||||||
<script>
|
<script>
|
||||||
var loc = window.location;
|
var loc = window.location;
|
||||||
@@ -72,10 +59,10 @@ if ($_POST['editing']) {
|
|||||||
</script>
|
</script>
|
||||||
';
|
';
|
||||||
} else {
|
} else {
|
||||||
print_error($result . ". Does your web server have permission to modify the rrd files?");
|
Toastr::error($result . ". Does your web server have permission to modify the rrd files?");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_error('Only administrative users may update the device hostname');
|
Toastr::error('Only administrative users may update the device hostname');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -83,16 +70,6 @@ if ($_POST['editing']) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$descr = $device['purpose'];
|
|
||||||
$override_sysLocation = $device['override_sysLocation'];
|
|
||||||
$override_sysLocation_string = $device['location'];
|
|
||||||
|
|
||||||
if ($updated && $update_message) {
|
|
||||||
print_message($update_message);
|
|
||||||
} elseif ($update_message) {
|
|
||||||
print_error($update_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<h3> Device Settings </h3>
|
<h3> Device Settings </h3>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -127,7 +104,7 @@ if ($updated && $update_message) {
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="descr" class="col-sm-2 control-label">Description:</label>
|
<label for="descr" class="col-sm-2 control-label">Description:</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<textarea id="descr" name="descr" class="form-control"><?php echo(display($device['purpose'])); ?></textarea>
|
<textarea id="descr" name="descr" class="form-control"><?php echo(display($device_model->purpose)); ?></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -139,7 +116,7 @@ if ($updated && $update_message) {
|
|||||||
|
|
||||||
foreach ($config['device_types'] as $type) {
|
foreach ($config['device_types'] as $type) {
|
||||||
echo(' <option value="'.$type['type'].'"');
|
echo(' <option value="'.$type['type'].'"');
|
||||||
if ($device['type'] == $type['type']) {
|
if ($device_model->type == $type['type']) {
|
||||||
echo(' selected="1"');
|
echo(' selected="1"');
|
||||||
$unknown = 0;
|
$unknown = 0;
|
||||||
}
|
}
|
||||||
@@ -157,21 +134,21 @@ if ($updated && $update_message) {
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input onclick="edit.sysLocation.disabled=!edit.override_sysLocation.checked" type="checkbox" name="override_sysLocation"
|
<input onclick="edit.sysLocation.disabled=!edit.override_sysLocation.checked" type="checkbox" name="override_sysLocation"
|
||||||
<?php
|
<?php
|
||||||
if ($override_sysLocation) {
|
if ($device_model->override_sysLocation) {
|
||||||
echo(' checked="1"');
|
echo(' checked="1"');
|
||||||
}
|
}
|
||||||
?> />
|
?> />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" title="To set coordinates, include [latitude,longitude]">
|
||||||
<div class="col-sm-2"></div>
|
<div class="col-sm-2"></div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input id="sysLocation" name="sysLocation" class="form-control"
|
<input id="sysLocation" name="sysLocation" class="form-control"
|
||||||
<?php
|
<?php
|
||||||
if (!$override_sysLocation) {
|
if (!$device_model->override_sysLocation) {
|
||||||
echo(' disabled="1"');
|
echo(' disabled="1"');
|
||||||
}
|
}
|
||||||
?> value="<?php echo($override_sysLocation_string); ?>" />
|
?> value="<?php echo display($device_model->location->location); ?>" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -206,7 +183,7 @@ if ($updated && $update_message) {
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input name="disabled" type="checkbox" id="disabled" value="1"
|
<input name="disabled" type="checkbox" id="disabled" value="1"
|
||||||
<?php
|
<?php
|
||||||
if ($device["disabled"]) {
|
if ($device_model->disabled) {
|
||||||
echo("checked=checked");
|
echo("checked=checked");
|
||||||
}
|
}
|
||||||
?> />
|
?> />
|
||||||
@@ -217,7 +194,7 @@ if ($updated && $update_message) {
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input name="ignore" type="checkbox" id="ignore" value="1"
|
<input name="ignore" type="checkbox" id="ignore" value="1"
|
||||||
<?php
|
<?php
|
||||||
if ($device['ignore']) {
|
if ($device_model->ignore) {
|
||||||
echo("checked=checked");
|
echo("checked=checked");
|
||||||
}
|
}
|
||||||
?> />
|
?> />
|
||||||
|
@@ -188,7 +188,7 @@ if ($format == "graph") {
|
|||||||
$where .= " )";
|
$where .= " )";
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM `devices` WHERE 1 ";
|
$query = "SELECT * FROM `devices`,locations WHERE devices.location_id = locations.id ";
|
||||||
|
|
||||||
if (isset($where)) {
|
if (isset($where)) {
|
||||||
$query .= $where;
|
$query .= $where;
|
||||||
@@ -325,18 +325,17 @@ if ($format == "graph") {
|
|||||||
|
|
||||||
$locations_options = "<select name='location' id='location' class='form-control input-sm'>";
|
$locations_options = "<select name='location' id='location' class='form-control input-sm'>";
|
||||||
$locations_options .= "<option value=''>All Locations</option>";
|
$locations_options .= "<option value=''>All Locations</option>";
|
||||||
foreach (getlocations() as $location) {
|
foreach (getlocations() as $location_row) {
|
||||||
if ($location) {
|
$location = clean_bootgrid($location_row['location']);
|
||||||
$location = clean_bootgrid($location);
|
$location_id = $location_row['id'];
|
||||||
if ($location == $vars['location']) {
|
if ($location == $vars['location'] || $location_id == $vars['location']) {
|
||||||
$location_selected = 'selected';
|
$location_selected = 'selected';
|
||||||
} else {
|
} else {
|
||||||
$location_selected = '';
|
$location_selected = '';
|
||||||
}
|
|
||||||
|
|
||||||
$ui_location = strlen($location) > 15 ? substr($location, 0, 15) . "..." : $location;
|
|
||||||
$locations_options .= "<option value='" . $location . "' " . $location_selected . ">" . $ui_location . "</option>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$ui_location = strlen($location) > 15 ? substr($location, 0, 15) . "..." : $location;
|
||||||
|
$locations_options .= "<option value='" . $location_id . "' " . $location_selected . ">" . $ui_location . "</option>";
|
||||||
}
|
}
|
||||||
$locations_options .= "</select>";
|
$locations_options .= "</select>";
|
||||||
|
|
||||||
|
@@ -68,7 +68,7 @@ if ($config['map']['engine'] == 'leaflet') {
|
|||||||
<script src='js/jquery.mousewheel.min.js'></script>
|
<script src='js/jquery.mousewheel.min.js'></script>
|
||||||
<?php
|
<?php
|
||||||
$x=0;
|
$x=0;
|
||||||
foreach (dbFetchRows("SELECT `hostname`,`devices`.`location`,`status`, COUNT(`status`) AS `total`,`lat`,`lng` FROM `devices` LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' GROUP BY `status`,`lat`,`lng` ORDER BY `status` ASC, `hostname`") as $map_devices) {
|
foreach (dbFetchRows("SELECT `hostname`,`location`,`status`, COUNT(`status`) AS `total`,`lat`,`lng` FROM `devices` LEFT JOIN `locations` ON `devices`.location_id=`locations`.`id` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' GROUP BY `status`,`lat`,`lng` ORDER BY `status` ASC, `hostname`") as $map_devices) {
|
||||||
$color = "#29FF3B";
|
$color = "#29FF3B";
|
||||||
$size = 15;
|
$size = 15;
|
||||||
$status = 'Up';
|
$status = 'Up';
|
||||||
|
@@ -72,7 +72,7 @@ if ($config['map']['engine'] == 'leaflet') {
|
|||||||
<script src='js/jquery.mousewheel.min.js'></script>
|
<script src='js/jquery.mousewheel.min.js'></script>
|
||||||
<?php
|
<?php
|
||||||
$x=0;
|
$x=0;
|
||||||
foreach (dbFetchRows("SELECT `hostname`,`devices`.`location`,`status`, COUNT(`status`) AS `total`,`lat`,`lng` FROM `devices` LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' GROUP BY `status`,`lat`,`lng` ORDER BY `status` ASC, `hostname`") as $map_devices) {
|
foreach (dbFetchRows("SELECT `hostname`,`location`,`status`, COUNT(`status`) AS `total`,`lat`,`lng` FROM `devices` LEFT JOIN `locations` ON `devices`.`location_id`=`locations`.`id` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' GROUP BY `status`,`lat`,`lng` ORDER BY `status` ASC, `hostname`") as $map_devices) {
|
||||||
$color = "#29FF3B";
|
$color = "#29FF3B";
|
||||||
$size = 15;
|
$size = 15;
|
||||||
$status = 'Up';
|
$status = 'Up';
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use LibreNMS\Authentication\LegacyAuth;
|
use App\Models\Location;
|
||||||
|
|
||||||
$pagetitle[] = 'Locations';
|
$pagetitle[] = 'Locations';
|
||||||
|
|
||||||
@@ -38,20 +38,13 @@ print_optionbar_end();
|
|||||||
|
|
||||||
echo '<table cellpadding="7" cellspacing="0" class="devicetable" width="100%">';
|
echo '<table cellpadding="7" cellspacing="0" class="devicetable" width="100%">';
|
||||||
|
|
||||||
foreach (getlocations() as $location) {
|
foreach (Location::hasAccess(Auth::user())->get() as $location) {
|
||||||
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
/** @var Location $location */
|
||||||
$num = dbFetchCell('SELECT COUNT(device_id) FROM devices WHERE location = ?', array($location));
|
$num = $location->devices()->count();
|
||||||
$net = dbFetchCell("SELECT COUNT(device_id) FROM devices WHERE location = ? AND type = 'network'", array($location));
|
$net = $location->devices()->where('type', 'network')->count();
|
||||||
$srv = dbFetchCell("SELECT COUNT(device_id) FROM devices WHERE location = ? AND type = 'server'", array($location));
|
$srv = $location->devices()->where('type', 'server')->count();
|
||||||
$fwl = dbFetchCell("SELECT COUNT(device_id) FROM devices WHERE location = ? AND type = 'firewall'", array($location));
|
$fwl = $location->devices()->where('type', 'firewall')->count();
|
||||||
$hostalerts = dbFetchCell("SELECT COUNT(device_id) FROM devices WHERE location = ? AND status = '0'", array($location));
|
$hostalerts = $location->devices()->isDown()->count();
|
||||||
} else {
|
|
||||||
$num = dbFetchCell('SELECT COUNT(D.device_id) FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND location = ?', array(LegacyAuth::id(), $location));
|
|
||||||
$net = dbFetchCell("SELECT COUNT(D.device_id) FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND location = ? AND D.type = 'network'", array(LegacyAuth::id(), $location));
|
|
||||||
$srv = dbFetchCell("SELECT COUNT(D.device_id) FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND location = ? AND type = 'server'", array(LegacyAuth::id(), $location));
|
|
||||||
$fwl = dbFetchCell("SELECT COUNT(D.device_id) FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND location = ? AND type = 'firewall'", array(LegacyAuth::id(), $location));
|
|
||||||
$hostalerts = dbFetchCell("SELECT COUNT(device_id) FROM devices AS D, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND location = ? AND status = '0'", array(LegacyAuth::id(), $location));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($hostalerts) {
|
if ($hostalerts) {
|
||||||
$alert = '<i class="fa fa-flag" style="color:red" aria-hidden="true"></i>';
|
$alert = '<i class="fa fa-flag" style="color:red" aria-hidden="true"></i>';
|
||||||
@@ -61,7 +54,7 @@ foreach (getlocations() as $location) {
|
|||||||
|
|
||||||
if ($location != '') {
|
if ($location != '') {
|
||||||
echo ' <tr class="locations">
|
echo ' <tr class="locations">
|
||||||
<td class="interface" width="300"><a class="list-bold" href="devices/location='.urlencode($location).'/">'.$location.'</a></td>
|
<td class="interface" width="300"><a class="list-bold" href="devices/location='.$location->id.'/">'.display($location->location).'</a></td>
|
||||||
<td width="100">'.$alert.'</td>
|
<td width="100">'.$alert.'</td>
|
||||||
<td width="100">'.$num.' devices</td>
|
<td width="100">'.$num.' devices</td>
|
||||||
<td width="100">'.$net.' network</td>
|
<td width="100">'.$net.' network</td>
|
||||||
@@ -78,7 +71,7 @@ foreach (getlocations() as $location) {
|
|||||||
$graph_array['width'] = '220';
|
$graph_array['width'] = '220';
|
||||||
$graph_array['to'] = $config['time']['now'];
|
$graph_array['to'] = $config['time']['now'];
|
||||||
$graph_array['legend'] = 'no';
|
$graph_array['legend'] = 'no';
|
||||||
$graph_array['id'] = $location;
|
$graph_array['id'] = $location->id;
|
||||||
|
|
||||||
include 'includes/print-graphrow.inc.php';
|
include 'includes/print-graphrow.inc.php';
|
||||||
|
|
||||||
|
@@ -246,15 +246,17 @@ if ((isset($vars['searchbar']) && $vars['searchbar'] != "hide") || !isset($vars[
|
|||||||
$output .= "<select title='Location' name='location' id='location' class='form-control input-sm'> ";
|
$output .= "<select title='Location' name='location' id='location' class='form-control input-sm'> ";
|
||||||
$output .= "<option value=''>All Locations</option>";
|
$output .= "<option value=''>All Locations</option>";
|
||||||
|
|
||||||
foreach (getlocations() as $location) {
|
foreach (getlocations() as $location_row) {
|
||||||
|
$location = $location_row['location'];
|
||||||
|
$location_id = $location_row['id'];
|
||||||
if ($location) {
|
if ($location) {
|
||||||
if ($location == $vars['location']) {
|
if ($location_id == $vars['location']) {
|
||||||
$locationselected = "selected";
|
$locationselected = "selected";
|
||||||
} else {
|
} else {
|
||||||
$locationselected = "";
|
$locationselected = "";
|
||||||
}
|
}
|
||||||
$ui_location = strlen($location) > 15 ? substr($location, 0, 15) . "..." : $location;
|
$ui_location = strlen($location) > 15 ? substr($location, 0, 15) . "..." : $location;
|
||||||
$output .= "<option value='" . clean_bootgrid($location) . "' " . $locationselected . ">" . clean_bootgrid($ui_location) . "</option>";
|
$output .= "<option value='$location_id' $locationselected>" . clean_bootgrid($ui_location) . "</option>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +320,7 @@ foreach ($vars as $var => $value) {
|
|||||||
$param[] = "%" . $value . "%";
|
$param[] = "%" . $value . "%";
|
||||||
break;
|
break;
|
||||||
case 'location':
|
case 'location':
|
||||||
$where .= " AND D.location LIKE ?";
|
$where .= " AND L.location LIKE ?";
|
||||||
$param[] = "%" . $value . "%";
|
$param[] = "%" . $value . "%";
|
||||||
break;
|
break;
|
||||||
case 'device_id':
|
case 'device_id':
|
||||||
@@ -402,7 +404,7 @@ if ($ignore_filter == 0 && $disabled_filter == 0) {
|
|||||||
$where .= " AND `I`.`ignore` = 0 AND `I`.`disabled` = 0 AND `I`.`deleted` = 0";
|
$where .= " AND `I`.`ignore` = 0 AND `I`.`disabled` = 0 AND `I`.`deleted` = 0";
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM `ports` AS I, `devices` AS D WHERE I.device_id = D.device_id " . $where . " " . $query_sort;
|
$query = "SELECT * FROM `ports` AS I, `devices` AS D, `locations` AS L WHERE I.device_id = D.device_id D.location_id = L.id" . $where . " " . $query_sort;
|
||||||
|
|
||||||
$row = 1;
|
$row = 1;
|
||||||
|
|
||||||
|
@@ -4,6 +4,26 @@ $no_refresh = true;
|
|||||||
|
|
||||||
$config_groups = get_config_by_group('external');
|
$config_groups = get_config_by_group('external');
|
||||||
|
|
||||||
|
$location_conf = [
|
||||||
|
[
|
||||||
|
'name' => 'geoloc.engine',
|
||||||
|
'descr' => 'Geocoding Engine',
|
||||||
|
'type' => 'select',
|
||||||
|
'options' => [
|
||||||
|
['value' => 'google', 'description' => 'Google Maps'],
|
||||||
|
['value' => 'openstreetmap', 'description' => 'OpenStreetMap'],
|
||||||
|
['value' => 'mapquest', 'description' => 'MapQuest'],
|
||||||
|
['value' => 'bing', 'description' => 'Bing Maps'],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'geoloc.api_key',
|
||||||
|
'descr' => 'Geocoding API Key',
|
||||||
|
'type' => 'text',
|
||||||
|
'class' => 'geoloc_api_key'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
$oxidized_conf = array(
|
$oxidized_conf = array(
|
||||||
array('name' => 'oxidized.enabled',
|
array('name' => 'oxidized.enabled',
|
||||||
'descr' => 'Enable Oxidized support',
|
'descr' => 'Enable Oxidized support',
|
||||||
@@ -84,12 +104,23 @@ echo '
|
|||||||
<form class="form-horizontal" role="form" action="" method="post">
|
<form class="form-horizontal" role="form" action="" method="post">
|
||||||
';
|
';
|
||||||
|
|
||||||
|
echo generate_dynamic_config_panel('Location Geocoding', $config_groups, $location_conf);
|
||||||
echo generate_dynamic_config_panel('Oxidized integration', $config_groups, $oxidized_conf);
|
echo generate_dynamic_config_panel('Oxidized integration', $config_groups, $oxidized_conf);
|
||||||
echo generate_dynamic_config_panel('Unix-agent integration', $config_groups, $unixagent_conf);
|
echo generate_dynamic_config_panel('Unix-agent integration', $config_groups, $unixagent_conf);
|
||||||
echo generate_dynamic_config_panel('RRDTool Setup', $config_groups, $rrdtool_conf);
|
echo generate_dynamic_config_panel('RRDTool Setup', $config_groups, $rrdtool_conf);
|
||||||
echo generate_dynamic_config_panel('PeeringDB Integration', $config_groups, $peeringdb_conf);
|
echo generate_dynamic_config_panel('PeeringDB Integration', $config_groups, $peeringdb_conf);
|
||||||
|
|
||||||
echo '
|
?>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
';
|
<script>
|
||||||
|
$('#geoloc\\.engine').change(function () {
|
||||||
|
var engine = this.value;
|
||||||
|
if (engine === 'openstreetmap') {
|
||||||
|
$('.geoloc_api_key').hide();
|
||||||
|
} else {
|
||||||
|
$('.geoloc_api_key').show();
|
||||||
|
}
|
||||||
|
}).change(); // trigger initially
|
||||||
|
</script>
|
||||||
|
@@ -415,7 +415,7 @@ function DescribeAlert($alert)
|
|||||||
{
|
{
|
||||||
$obj = array();
|
$obj = array();
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$device = dbFetchRow('SELECT hostname, sysName, sysDescr, sysContact, os, type, ip, hardware, version, location, purpose, notes, uptime, status, status_reason FROM devices WHERE device_id = ?', array($alert['device_id']));
|
$device = dbFetchRow('SELECT hostname, sysName, sysDescr, sysContact, os, type, ip, hardware, version, purpose, notes, uptime, status, status_reason, locations.location FROM devices, locations WHERE locations.id = location_id && device_id = ?', array($alert['device_id']));
|
||||||
$attribs = get_dev_attribs($alert['device_id']);
|
$attribs = get_dev_attribs($alert['device_id']);
|
||||||
|
|
||||||
$obj['hostname'] = $device['hostname'];
|
$obj['hostname'] = $device['hostname'];
|
||||||
|
@@ -366,7 +366,7 @@ function device_by_id_cache($device_id, $refresh = false)
|
|||||||
if (!$refresh && isset($cache['devices']['id'][$device_id]) && is_array($cache['devices']['id'][$device_id])) {
|
if (!$refresh && isset($cache['devices']['id'][$device_id]) && is_array($cache['devices']['id'][$device_id])) {
|
||||||
$device = $cache['devices']['id'][$device_id];
|
$device = $cache['devices']['id'][$device_id];
|
||||||
} else {
|
} else {
|
||||||
$device = dbFetchRow("SELECT `devices`.*, `lat`, `lng` FROM `devices` LEFT JOIN locations ON `devices`.`location`=`locations`.`location` WHERE `device_id` = ?", array($device_id));
|
$device = dbFetchRow("SELECT `devices`.*, `location`, `lat`, `lng` FROM `devices` LEFT JOIN locations ON `devices`.location_id=`locations`.`id` WHERE `device_id` = ?", [$device_id]);
|
||||||
$device['attribs'] = get_dev_attribs($device['device_id']);
|
$device['attribs'] = get_dev_attribs($device['device_id']);
|
||||||
load_os($device);
|
load_os($device);
|
||||||
|
|
||||||
@@ -1122,14 +1122,16 @@ function ceph_rrd($gtype)
|
|||||||
/**
|
/**
|
||||||
* Parse location field for coordinates
|
* Parse location field for coordinates
|
||||||
* @param string location The location field to look for coords in.
|
* @param string location The location field to look for coords in.
|
||||||
* @return array Containing the lat and lng coords
|
* @return array|bool Containing the lat and lng coords
|
||||||
**/
|
**/
|
||||||
function parse_location($location)
|
function parse_location($location)
|
||||||
{
|
{
|
||||||
preg_match('/(\[)(-?[0-9\. ]+),[ ]*(-?[0-9\. ]+)(\])/', $location, $tmp_loc);
|
preg_match('/\[(-?[0-9. ]+), *(-?[0-9. ]+)\]/', $location, $tmp_loc);
|
||||||
if (is_numeric($tmp_loc[2]) && is_numeric($tmp_loc[3])) {
|
if (is_numeric($tmp_loc[1]) && is_numeric($tmp_loc[2])) {
|
||||||
return array('lat' => $tmp_loc[2], 'lng' => $tmp_loc[3]);
|
return ['lat' => $tmp_loc[1], 'lng' => $tmp_loc[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}//end parse_location()
|
}//end parse_location()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1354,11 +1356,16 @@ function ResolveGlues($tables, $target, $x = 0, $hist = array(), $last = array()
|
|||||||
'sensors_to_state_indexes.sensor_id',
|
'sensors_to_state_indexes.sensor_id',
|
||||||
"sensors.$target",
|
"sensors.$target",
|
||||||
));
|
));
|
||||||
} elseif ($table == 'application_metrics' && $target = 'device_id') {
|
} elseif ($table == 'application_metrics' && $target == 'device_id') {
|
||||||
return array_merge($last, array(
|
return array_merge($last, array(
|
||||||
'application_metrics.app_id',
|
'application_metrics.app_id',
|
||||||
"applications.$target",
|
"applications.$target",
|
||||||
));
|
));
|
||||||
|
} elseif ($table == 'locations' && $target == 'device_id') {
|
||||||
|
return array_merge($last, [
|
||||||
|
'locations.id',
|
||||||
|
'devices.device_id.location_id'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$glues = dbFetchRows('SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME LIKE "%\_id"', array($table));
|
$glues = dbFetchRows('SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME LIKE "%\_id"', array($table));
|
||||||
|
@@ -916,8 +916,8 @@ $config['unix-agent-read-time-out'] = 10;
|
|||||||
// seconds
|
// seconds
|
||||||
|
|
||||||
// Lat / Lon support for maps
|
// Lat / Lon support for maps
|
||||||
$config['geoloc']['latlng'] = true; // True to enable translation of location to latlng co-ordinates
|
#$config['geoloc']['latlng'] = true; // True to enable translation of location to latlng co-ordinates
|
||||||
$config['geoloc']['engine'] = 'google';
|
#$config['geoloc']['engine'] = 'google';
|
||||||
$config['map']['engine'] = 'leaflet';
|
$config['map']['engine'] = 'leaflet';
|
||||||
$config['mapael']['default_map'] = 'maps/world_countries.js';
|
$config['mapael']['default_map'] = 'maps/world_countries.js';
|
||||||
$config['leaflet']['default_lat'] = '51.4800';
|
$config['leaflet']['default_lat'] = '51.4800';
|
||||||
|
@@ -127,7 +127,12 @@ function GenGroupSQL($pattern, $search = '', $extra = 0)
|
|||||||
list($tmp,$last) = explode('.', $glue);
|
list($tmp,$last) = explode('.', $glue);
|
||||||
$qry .= $glue.' = ';
|
$qry .= $glue.' = ';
|
||||||
} else {
|
} else {
|
||||||
list($tmp,$new) = explode('.', $glue);
|
$parts = explode('.', $glue);
|
||||||
|
if (count($parts) == 3) {
|
||||||
|
list($tmp, $new, $last) = $parts;
|
||||||
|
} else {
|
||||||
|
list($tmp,$new) = $parts;
|
||||||
|
}
|
||||||
$qry .= $tmp.'.'.$last.' && '.$tmp.'.'.$new.' = ';
|
$qry .= $tmp.'.'.$last.' && '.$tmp.'.'.$new.' = ';
|
||||||
$last = $new;
|
$last = $new;
|
||||||
}
|
}
|
||||||
|
@@ -2466,13 +2466,17 @@ function get_schema_list()
|
|||||||
function get_db_schema()
|
function get_db_schema()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return \LibreNMS\DB\Eloquent::DB()
|
$db = \LibreNMS\DB\Eloquent::DB();
|
||||||
->table('dbSchema')
|
if ($db) {
|
||||||
->orderBy('version', 'DESC')
|
return $db->table('dbSchema')
|
||||||
->value('version');
|
->orderBy('version', 'DESC')
|
||||||
|
->value('version');
|
||||||
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
return 0;
|
// return default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
* See COPYING for more details.
|
* See COPYING for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Models\Location;
|
||||||
|
use LibreNMS\Config;
|
||||||
use LibreNMS\RRD\RrdDefinition;
|
use LibreNMS\RRD\RrdDefinition;
|
||||||
|
|
||||||
$snmpdata = snmp_get_multi_oid($device, 'sysUpTime.0 sysLocation.0 sysContact.0 sysName.0 sysObjectID.0 sysDescr.0', '-OQnUt', 'SNMPv2-MIB');
|
$snmpdata = snmp_get_multi_oid($device, 'sysUpTime.0 sysLocation.0 sysContact.0 sysName.0 sysObjectID.0 sysDescr.0', '-OQnUt', 'SNMPv2-MIB');
|
||||||
@@ -79,14 +81,23 @@ foreach (array('sysContact', 'sysObjectID', 'sysName', 'sysDescr') as $elem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($poll_device['sysLocation'] && $device['location'] != $poll_device['sysLocation'] && $device['override_sysLocation'] == 0) {
|
if ($device['override_sysLocation'] == 0 && $poll_device['sysLocation']) {
|
||||||
$update_array['location'] = $poll_device['sysLocation'];
|
/** @var Location $location */
|
||||||
$device['location'] = $poll_device['sysLocation'];
|
$location = Location::firstOrCreate(['location' => $poll_device['sysLocation']]);
|
||||||
log_event('Location -> ' . $poll_device['sysLocation'], $device, 'system', 3);
|
|
||||||
|
if ($device['location_id'] != $location->id) {
|
||||||
|
$device['location_id'] = $location->id;
|
||||||
|
$update_array['location_id'] = $location->id;
|
||||||
|
log_event('Location -> ' . $location->location, $device, 'system', 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['geoloc']['latlng'] === true) {
|
// make sure the location has coordinates
|
||||||
location_to_latlng($device);
|
if (Config::get('geoloc.latlng', true) && ($location || $location = Location::find($device['location_id']))) {
|
||||||
|
if (!$location->hasCoordinates()) {
|
||||||
|
$location->lookupCoordinates();
|
||||||
|
$location->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($snmpdata, $uptime_data, $uptime, $tags, $poll_device);
|
unset($snmpdata, $uptime_data, $uptime, $tags, $poll_device);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
use LibreNMS\RRD\RrdDefinition;
|
use LibreNMS\RRD\RrdDefinition;
|
||||||
use LibreNMS\Exceptions\JsonAppException;
|
use LibreNMS\Exceptions\JsonAppException;
|
||||||
use LibreNMS\Exceptions\JsonAppPollingFailedException;
|
use LibreNMS\Exceptions\JsonAppPollingFailedException;
|
||||||
@@ -524,108 +525,6 @@ function get_main_serial($device)
|
|||||||
}
|
}
|
||||||
}//end get_main_serial()
|
}//end get_main_serial()
|
||||||
|
|
||||||
|
|
||||||
function location_to_latlng($device)
|
|
||||||
{
|
|
||||||
global $config;
|
|
||||||
if (function_check('curl_version') !== true) {
|
|
||||||
d_echo("Curl support for PHP not enabled\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$bad_loc = false;
|
|
||||||
$device_location = $device['location'];
|
|
||||||
if (!empty($device_location)) {
|
|
||||||
$new_device_location = preg_replace("/ /", "+", $device_location);
|
|
||||||
$new_device_location = preg_replace('/[^A-Za-z0-9\-\+]/', '', $new_device_location); // Removes special chars.
|
|
||||||
// We have a location string for the device.
|
|
||||||
$loc = parse_location($device_location);
|
|
||||||
if (!is_array($loc)) {
|
|
||||||
$loc = dbFetchRow("SELECT `lat`,`lng` FROM `locations` WHERE `location`=? LIMIT 1", array($device_location));
|
|
||||||
}
|
|
||||||
if (is_array($loc) === false) {
|
|
||||||
// Grab data from which ever Geocode service we use.
|
|
||||||
switch ($config['geoloc']['engine']) {
|
|
||||||
case "google":
|
|
||||||
default:
|
|
||||||
d_echo("Google geocode engine being used\n");
|
|
||||||
$api_key = ($config['geoloc']['api_key']);
|
|
||||||
if (!empty($api_key)) {
|
|
||||||
$api_url = "https://maps.googleapis.com/maps/api/geocode/json?address=$new_device_location&key=$api_key";
|
|
||||||
} else {
|
|
||||||
d_echo("No geocode API key set\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "mapquest":
|
|
||||||
d_echo("Mapquest geocode engine being used\n");
|
|
||||||
$api_key = ($config['geoloc']['api_key']);
|
|
||||||
if (!empty($api_key)) {
|
|
||||||
$api_url = "http://open.mapquestapi.com/geocoding/v1/address?key=$api_key&location=$new_device_location&thumbMaps=false";
|
|
||||||
} else {
|
|
||||||
d_echo("No geocode API key set\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "bing":
|
|
||||||
d_echo("Bing geocode engine being used\n");
|
|
||||||
$api_key = ($config['geoloc']['api_key']);
|
|
||||||
if (!empty($api_key)) {
|
|
||||||
$api_url = "http://dev.virtualearth.net/REST/v1/Locations?addressLine=$new_device_location&key=$api_key";
|
|
||||||
} else {
|
|
||||||
d_echo("No geocode API key set\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$curl_init = curl_init($api_url);
|
|
||||||
set_curl_proxy($curl_init);
|
|
||||||
curl_setopt($curl_init, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($curl_init, CURLOPT_TIMEOUT, 2);
|
|
||||||
curl_setopt($curl_init, CURLOPT_TIMEOUT_MS, 2000);
|
|
||||||
curl_setopt($curl_init, CURLOPT_CONNECTTIMEOUT, 5);
|
|
||||||
$data = json_decode(curl_exec($curl_init), true);
|
|
||||||
// Parse the data from the specific Geocode services.
|
|
||||||
d_echo(json_encode($data));
|
|
||||||
switch ($config['geoloc']['engine']) {
|
|
||||||
case "google":
|
|
||||||
default:
|
|
||||||
if ($data['status'] == 'OK') {
|
|
||||||
$loc = $data['results'][0]['geometry']['location'];
|
|
||||||
} else {
|
|
||||||
$bad_loc = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "mapquest":
|
|
||||||
if ($data['info']['statuscode'] == 0) {
|
|
||||||
$loc['lat'] = $data['results'][0]['locations'][0]['latLng']['lat'];
|
|
||||||
$loc['lng'] = $data['results'][0]['locations'][0]['latLng']['lng'];
|
|
||||||
} else {
|
|
||||||
$bad_loc = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "bing":
|
|
||||||
if ($data['statusDescription'] == 'OK') {
|
|
||||||
$loc['lat'] = $data['resourceSets'][0]["resources"][0]["point"]["coordinates"][0];
|
|
||||||
$loc['lng'] = $data['resourceSets'][0]["resources"][0]["point"]["coordinates"][1];
|
|
||||||
} else {
|
|
||||||
$bad_loc = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($bad_loc === true) {
|
|
||||||
d_echo("Bad lat / lng received\n");
|
|
||||||
} else {
|
|
||||||
$loc['timestamp'] = array('NOW()');
|
|
||||||
$loc['location'] = $device_location;
|
|
||||||
if (dbInsert($loc, 'locations')) {
|
|
||||||
d_echo("Device lat/lng created\n");
|
|
||||||
} else {
|
|
||||||
d_echo("Device lat/lng could not be created\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d_echo("Using cached lat/lng from other device\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}// end location_to_latlng()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the application status and output in the database.
|
* Update the application status and output in the database.
|
||||||
*
|
*
|
||||||
|
@@ -451,7 +451,7 @@ devices:
|
|||||||
- { Field: version, Type: text, 'Null': true, Extra: '' }
|
- { Field: version, Type: text, 'Null': true, Extra: '' }
|
||||||
- { Field: hardware, Type: text, 'Null': true, Extra: '' }
|
- { Field: hardware, Type: text, 'Null': true, Extra: '' }
|
||||||
- { Field: features, Type: text, 'Null': true, Extra: '' }
|
- { Field: features, Type: text, 'Null': true, Extra: '' }
|
||||||
- { Field: location, Type: text, 'Null': true, Extra: '' }
|
- { Field: location_id, Type: int(11), 'Null': true, Extra: '' }
|
||||||
- { Field: os, Type: varchar(32), 'Null': true, Extra: '' }
|
- { Field: os, Type: varchar(32), 'Null': true, Extra: '' }
|
||||||
- { Field: status, Type: tinyint(1), 'Null': false, Extra: '', Default: '0' }
|
- { Field: status, Type: tinyint(1), 'Null': false, Extra: '', Default: '0' }
|
||||||
- { Field: status_reason, Type: varchar(50), 'Null': false, Extra: '' }
|
- { Field: status_reason, Type: varchar(50), 'Null': false, Extra: '' }
|
||||||
@@ -772,12 +772,13 @@ loadbalancer_vservers:
|
|||||||
locations:
|
locations:
|
||||||
Columns:
|
Columns:
|
||||||
- { Field: id, Type: int(11), 'Null': false, Extra: auto_increment }
|
- { Field: id, Type: int(11), 'Null': false, Extra: auto_increment }
|
||||||
- { Field: location, Type: text, 'Null': false, Extra: '' }
|
- { Field: location, Type: varchar(255), 'Null': false, Extra: '' }
|
||||||
- { Field: lat, Type: 'double(10,6)', 'Null': false, Extra: '' }
|
- { Field: lat, Type: 'double(10,6)', 'Null': true, Extra: '' }
|
||||||
- { Field: lng, Type: 'double(10,6)', 'Null': false, Extra: '' }
|
- { Field: lng, Type: 'double(10,6)', 'Null': true, Extra: '' }
|
||||||
- { Field: timestamp, Type: datetime, 'Null': false, Extra: '' }
|
- { Field: timestamp, Type: datetime, 'Null': false, Extra: '' }
|
||||||
Indexes:
|
Indexes:
|
||||||
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
||||||
|
locations_location_uindex: { Name: locations_location_uindex, Columns: [location], Unique: true, Type: BTREE }
|
||||||
mac_accounting:
|
mac_accounting:
|
||||||
Columns:
|
Columns:
|
||||||
- { Field: ma_id, Type: int(11), 'Null': false, Extra: auto_increment }
|
- { Field: ma_id, Type: int(11), 'Null': false, Extra: auto_increment }
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
use LibreNMS\Config;
|
use LibreNMS\Config;
|
||||||
|
|
||||||
$init_modules = array('polling', 'alerts');
|
$init_modules = ['polling', 'alerts', 'laravel'];
|
||||||
require __DIR__ . '/includes/init.php';
|
require __DIR__ . '/includes/init.php';
|
||||||
|
|
||||||
$poller_start = microtime(true);
|
$poller_start = microtime(true);
|
||||||
|
@@ -118,8 +118,9 @@
|
|||||||
@if($locations)
|
@if($locations)
|
||||||
<li role="presentation" class="divider"></li>
|
<li role="presentation" class="divider"></li>
|
||||||
<li class="dropdown-submenu">
|
<li class="dropdown-submenu">
|
||||||
<a href="#"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> Geo Locations</a>
|
<a href="#"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> @lang('Geo Locations')</a>
|
||||||
<ul class="dropdown-menu scrollable-menu">
|
<ul class="dropdown-menu scrollable-menu">
|
||||||
|
<li><a href="{{ url('locations') }}"><i class="fa fa-map-marker fa-fw fa-lg" aria-hidden="true"></i> @lang('All Locations')</a></li>
|
||||||
@foreach($locations as $location)
|
@foreach($locations as $location)
|
||||||
<li><a href="{{ url("devices/location=" . urlencode($location)) }}"><i class="fa fa-building fa-fw fa-lg" aria-hidden="true"></i> {{ $location }}</a></li>
|
<li><a href="{{ url("devices/location=" . urlencode($location)) }}"><i class="fa fa-building fa-fw fa-lg" aria-hidden="true"></i> {{ $location }}</a></li>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
17
sql-schema/272.sql
Normal file
17
sql-schema/272.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ALTER TABLE devices ADD location_id int NULL AFTER location;
|
||||||
|
ALTER TABLE locations MODIFY lat double(10,6);
|
||||||
|
ALTER TABLE locations MODIFY lng double(10,6);
|
||||||
|
ALTER TABLE locations MODIFY location varchar(255) NOT NULL;
|
||||||
|
|
||||||
|
INSERT INTO locations (location, timestamp) SELECT devices.location, NOW() FROM devices WHERE devices.location IS NOT NULL AND NOT EXISTS (SELECT location FROM locations WHERE location = devices.location);
|
||||||
|
DELETE t1 FROM locations t1 INNER JOIN locations t2 WHERE t1.id < t2.id AND t1.location = t2.location;
|
||||||
|
CREATE UNIQUE INDEX locations_location_uindex ON locations (location);
|
||||||
|
|
||||||
|
UPDATE devices INNER JOIN locations ON devices.location = locations.location SET devices.location_id = locations.id;
|
||||||
|
ALTER TABLE devices DROP location;
|
||||||
|
|
||||||
|
UPDATE alert_rules SET builder=REPLACE(builder, 'devices.location', 'locations.location');
|
||||||
|
UPDATE device_groups SET pattern=REPLACE(pattern, 'devices.location', 'locations.location');
|
||||||
|
|
||||||
|
INSERT INTO config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('geoloc.engine','','','Geocoding Engine','external',0,'location',0,'0','0');
|
||||||
|
INSERT INTO config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('geoloc.api_key','','','Geocoding API Key (Required to function)','external',0,'location',0,'0','0');
|
@@ -7,4 +7,5 @@ use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
|||||||
abstract class LaravelTestCase extends BaseTestCase
|
abstract class LaravelTestCase extends BaseTestCase
|
||||||
{
|
{
|
||||||
use CreatesApplication;
|
use CreatesApplication;
|
||||||
|
use SnmpsimHelpers;
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,7 @@ class OSModulesTest extends DBTestCase
|
|||||||
*/
|
*/
|
||||||
public function testOS($os, $variant, $modules)
|
public function testOS($os, $variant, $modules)
|
||||||
{
|
{
|
||||||
$this->requreSnmpsim(); // require snmpsim for tests
|
$this->requireSnmpsim(); // require snmpsim for tests
|
||||||
global $snmpsim;
|
global $snmpsim;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@@ -45,11 +45,20 @@ class SchemaTest extends TestCase
|
|||||||
"devices" => [
|
"devices" => [
|
||||||
"Columns" => [
|
"Columns" => [
|
||||||
["Field" => "device_id", "Type" => "int(11) unsigned", "Null" => false, "Extra" => "auto_increment"],
|
["Field" => "device_id", "Type" => "int(11) unsigned", "Null" => false, "Extra" => "auto_increment"],
|
||||||
|
["Field" => "location_id", "Type" => "int(11)", "Null" => true, "Extra" => ""],
|
||||||
],
|
],
|
||||||
"Indexes" => [
|
"Indexes" => [
|
||||||
"PRIMARY" => ["Name" => "PRIMARY", "Columns" => ["device_id"], "Unique" => true, "Type" => "BTREE"],
|
"PRIMARY" => ["Name" => "PRIMARY", "Columns" => ["device_id"], "Unique" => true, "Type" => "BTREE"],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"locations" => [
|
||||||
|
"Columns" => [
|
||||||
|
["Field" => "id", "Type" => "int(11)", "Null" => false, "Extra" => "auto_increment"],
|
||||||
|
],
|
||||||
|
"Indexes" => [
|
||||||
|
"PRIMARY" => ["Name" => "PRIMARY", "Columns" => ["id"], "Unique" => true, "Type" => "BTREE"],
|
||||||
|
]
|
||||||
|
],
|
||||||
"ports" => [
|
"ports" => [
|
||||||
"Columns" => [
|
"Columns" => [
|
||||||
["Field" => "port_id", "Type" => "int(11)", "Null" => false, "Extra" => "auto_increment"],
|
["Field" => "port_id", "Type" => "int(11)", "Null" => false, "Extra" => "auto_increment"],
|
||||||
@@ -123,7 +132,8 @@ class SchemaTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'bills' => [],
|
'bills' => [],
|
||||||
'bill_ports' => ['bills', 'ports'],
|
'bill_ports' => ['bills', 'ports'],
|
||||||
'devices' => [],
|
'devices' => ['locations'],
|
||||||
|
'locations' => [],
|
||||||
'ports' => ['devices'],
|
'ports' => ['devices'],
|
||||||
'sensors' => ['devices'],
|
'sensors' => ['devices'],
|
||||||
'sensors_to_state_indexes' => ['sensors', 'state_indexes'],
|
'sensors_to_state_indexes' => ['sensors', 'state_indexes'],
|
||||||
@@ -139,6 +149,7 @@ class SchemaTest extends TestCase
|
|||||||
$schema = $this->getSchemaMock();
|
$schema = $this->getSchemaMock();
|
||||||
|
|
||||||
$this->assertEquals(['devices'], $schema->findRelationshipPath('devices'));
|
$this->assertEquals(['devices'], $schema->findRelationshipPath('devices'));
|
||||||
|
$this->assertEquals(['locations', 'devices'], $schema->findRelationshipPath('locations'));
|
||||||
$this->assertEquals(['devices', 'ports'], $schema->findRelationshipPath('ports'));
|
$this->assertEquals(['devices', 'ports'], $schema->findRelationshipPath('ports'));
|
||||||
$this->assertEquals(['devices', 'ports', 'bill_ports'], $schema->findRelationshipPath('bill_ports'));
|
$this->assertEquals(['devices', 'ports', 'bill_ports'], $schema->findRelationshipPath('bill_ports'));
|
||||||
$this->assertEquals(['devices', 'ports', 'bill_ports', 'bills'], $schema->findRelationshipPath('bills'));
|
$this->assertEquals(['devices', 'ports', 'bill_ports', 'bills'], $schema->findRelationshipPath('bills'));
|
||||||
|
36
tests/SnmpsimHelpers.php
Normal file
36
tests/SnmpsimHelpers.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChecksSnmpsim.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 2018 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Tests;
|
||||||
|
|
||||||
|
trait SnmpsimHelpers
|
||||||
|
{
|
||||||
|
public function requireSnmpsim()
|
||||||
|
{
|
||||||
|
if (!getenv('SNMPSIM')) {
|
||||||
|
$this->markTestSkipped('Snmpsim required for this test. Set SNMPSIM=1 to enable.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,8 @@ use LibreNMS\Util\Snmpsim;
|
|||||||
|
|
||||||
abstract class TestCase extends \PHPUnit_Framework_TestCase
|
abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
use SnmpsimHelpers;
|
||||||
|
|
||||||
/** @var Snmpsim snmpsim instance */
|
/** @var Snmpsim snmpsim instance */
|
||||||
protected $snmpsim = null;
|
protected $snmpsim = null;
|
||||||
|
|
||||||
@@ -57,11 +59,4 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
|||||||
\LibreNMS\DB\Eloquent::DB()->rollBack();
|
\LibreNMS\DB\Eloquent::DB()->rollBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requreSnmpsim()
|
|
||||||
{
|
|
||||||
if (!getenv('SNMPSIM')) {
|
|
||||||
$this->markTestSkipped('Snmpsim required for this test. Set SNMPSIM=1 to enable.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -37,6 +37,8 @@ ports:
|
|||||||
os:
|
os:
|
||||||
devices:
|
devices:
|
||||||
included_fields: [sysName, sysObjectID, sysDescr, sysContact, version, hardware, features, location, os, type, serial, icon]
|
included_fields: [sysName, sysObjectID, sysDescr, sysContact, version, hardware, features, location, os, type, serial, icon]
|
||||||
|
joins:
|
||||||
|
- { left: devices.location_id, right: locations.id, select: [location] }
|
||||||
processors:
|
processors:
|
||||||
processors:
|
processors:
|
||||||
excluded_fields: [device_id, processor_id]
|
excluded_fields: [device_id, processor_id]
|
||||||
|
Reference in New Issue
Block a user