API mac search (#12964)

* API find a switchport with the mac from device

* fix style

* convert SQL to Eloquent

* convert SQL to Eloquent

* git mistake

* Global use App\Models\Port

* git mistake partII

* Refractor Eloquent - Not finish but easier to help for others

* Better Eloquent Query without filter option

* Validation

* fix style

* Add filter option and DOC

* convert to the better macToHex method

* add a maxToHex unit test

* fix style

* fix style

* fix syle - seems my dev:check is running again :-)

* Fix phpStan

* phpStan #2
This commit is contained in:
Kevin Zink
2021-08-10 02:33:04 +02:00
committed by GitHub
parent 9c534a1a90
commit 93209a0fc8
4 changed files with 201 additions and 27 deletions

View File

@@ -90,6 +90,111 @@ Output:
}
```
### `ports_with_associated_mac`
Search for ports matching the search mac.
Route: `/api/v0/ports/mac/:search?filter=first`
- search a mac address in fdb and print the ports ordered by the mac count of the associated port.
Input:
-
Example:
```curl
curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/ports/mac/00:11:22:33:44:55
curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/ports/mac/001122.334455?filter=first
curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/ports/mac/001122334455?filter=first
```
Output:
```json
{
"status": "ok",
"message": "",
"port": [
{
"port_id": "323",
"device_id": "55",
"port_descr_type": null,
"port_descr_descr": null,
"port_descr_circuit": null,
"port_descr_speed": null,
"port_descr_notes": null,
"ifDescr": "GigabitEthernet0/0/0",
"ifName": "Gi0/0/0",
"portName": null,
"ifIndex": "1",
"ifSpeed": "1000000000",
"ifConnectorPresent": "true",
"ifPromiscuousMode": "false",
"ifHighSpeed": "1000",
"ifOperStatus": "up",
"ifOperStatus_prev": null,
"ifAdminStatus": "up",
"ifAdminStatus_prev": null,
"ifDuplex": "fullDuplex",
"ifMtu": "1560",
"ifType": "ethernetCsmacd",
"ifAlias": "ASR Interconnect Trunk",
"ifPhysAddress": "84bf20853e00",
"ifHardType": null,
"ifLastChange": "42407358",
"ifVlan": "",
"ifTrunk": "",
"ifVrf": "0",
"counter_in": null,
"counter_out": null,
"ignore": "0",
"disabled": "0",
"detailed": "0",
"deleted": "0",
"pagpOperationMode": null,
"pagpPortState": null,
"pagpPartnerDeviceId": null,
"pagpPartnerLearnMethod": null,
"pagpPartnerIfIndex": null,
"pagpPartnerGroupIfIndex": null,
"pagpPartnerDeviceName": null,
"pagpEthcOperationMode": null,
"pagpDeviceId": null,
"pagpGroupIfIndex": null,
"ifInUcastPkts": "128518576",
"ifInUcastPkts_prev": "128517284",
"ifInUcastPkts_delta": "1292",
"ifInUcastPkts_rate": "4",
"ifOutUcastPkts": "128510560",
"ifOutUcastPkts_prev": "128509268",
"ifOutUcastPkts_delta": "1292",
"ifOutUcastPkts_rate": "4",
"ifInErrors": "0",
"ifInErrors_prev": "0",
"ifInErrors_delta": "0",
"ifInErrors_rate": "0",
"ifOutErrors": "0",
"ifOutErrors_prev": "0",
"ifOutErrors_delta": "0",
"ifOutErrors_rate": "0",
"ifInOctets": "12827393730",
"ifInOctets_prev": "12827276736",
"ifInOctets_delta": "116994",
"ifInOctets_rate": "387",
"ifOutOctets": "14957481766",
"ifOutOctets_prev": "14957301765",
"ifOutOctets_delta": "180001",
"ifOutOctets_rate": "596",
"poll_time": "1483779150",
"poll_prev": "1483778848",
"poll_period": "302"
}
]
}
### `get_port_info`
Get all info for a particular port.

View File

@@ -17,6 +17,7 @@ use App\Models\Device;
use App\Models\DeviceGroup;
use App\Models\DeviceOutage;
use App\Models\OspfPort;
use App\Models\Port;
use App\Models\PortGroup;
use App\Models\PortsFdb;
use App\Models\Sensor;
@@ -32,6 +33,7 @@ use LibreNMS\Data\Store\Datastore;
use LibreNMS\Exceptions\InvalidIpException;
use LibreNMS\Util\IP;
use LibreNMS\Util\IPv4;
use LibreNMS\Util\Rewrite;
function api_success($result, $result_name, $message = null, $code = 200, $count = null, $extra = null)
{
@@ -465,8 +467,8 @@ function device_availability(Illuminate\Http\Request $request)
return check_device_permission($device_id, function ($device_id) {
$availabilities = Availability::select('duration', 'availability_perc')
->where('device_id', '=', $device_id)
->orderBy('duration', 'ASC');
->where('device_id', '=', $device_id)
->orderBy('duration', 'ASC');
return api_success($availabilities->get(), 'availability');
});
@@ -486,8 +488,8 @@ function device_outages(Illuminate\Http\Request $request)
return check_device_permission($device_id, function ($device_id) {
$outages = DeviceOutage::select('going_down', 'up_again')
->where('device_id', '=', $device_id)
->orderBy('going_down', 'DESC');
->where('device_id', '=', $device_id)
->orderBy('going_down', 'DESC');
return api_success($outages->get(), 'outages');
});
@@ -653,7 +655,7 @@ function list_ospf(Illuminate\Http\Request $request)
function list_ospf_ports(Illuminate\Http\Request $request)
{
$ospf_ports = OspfPort::hasAccess(Auth::user())
->get();
->get();
if ($ospf_ports->isEmpty()) {
return api_error(404, 'Ospf ports do not exist');
}
@@ -990,13 +992,13 @@ function search_ports(Illuminate\Http\Request $request)
{
$search = $request->route('search');
$value = "%$search%";
$ports = \App\Models\Port::hasAccess(Auth::user())
->select(['device_id', 'port_id', 'ifIndex', 'ifName'])
->where('ifAlias', 'like', $value)
->orWhere('ifDescr', 'like', $value)
->orWhere('ifName', 'like', $value)
->orderBy('ifName')
->get();
$ports = Port::hasAccess(Auth::user())
->select(['device_id', 'port_id', 'ifIndex', 'ifName'])
->where('ifAlias', 'like', $value)
->orWhere('ifDescr', 'like', $value)
->orWhere('ifName', 'like', $value)
->orderBy('ifName')
->get();
if ($ports->isEmpty()) {
return api_error(404, 'No ports found');
@@ -1357,15 +1359,15 @@ function list_oxidized(Illuminate\Http\Request $request)
{
$return = [];
$devices = Device::query()
->where('disabled', 0)
->when($request->route('hostname'), function ($query, $hostname) {
return $query->where('hostname', $hostname);
})
->whereNotIn('type', Config::get('oxidized.ignore_types', []))
->whereNotIn('os', Config::get('oxidized.ignore_os', []))
->whereAttributeDisabled('override_Oxidized_disable')
->select(['hostname', 'sysName', 'sysDescr', 'hardware', 'os', 'ip', 'location_id'])
->get();
->where('disabled', 0)
->when($request->route('hostname'), function ($query, $hostname) {
return $query->where('hostname', $hostname);
})
->whereNotIn('type', Config::get('oxidized.ignore_types', []))
->whereNotIn('os', Config::get('oxidized.ignore_os', []))
->whereAttributeDisabled('override_Oxidized_disable')
->select(['hostname', 'sysName', 'sysDescr', 'hardware', 'os', 'ip', 'location_id'])
->get();
/** @var Device $device */
foreach ($devices as $device) {
@@ -1614,8 +1616,8 @@ function get_bill_history_graphdata(Illuminate\Http\Request $request)
}
return ! isset($graph_data) ?
api_error(400, "Unsupported graph type $graph_type") :
api_success($graph_data, 'graph_data');
api_error(400, "Unsupported graph type $graph_type") :
api_success($graph_data, 'graph_data');
});
}
@@ -2145,10 +2147,10 @@ function list_fdb(Illuminate\Http\Request $request)
$mac = $request->route('mac');
$fdb = PortsFdb::hasAccess(Auth::user())
->when(! empty($mac), function (Builder $query) use ($mac) {
return $query->where('mac_address', $mac);
})
->get();
->when(! empty($mac), function (Builder $query) use ($mac) {
return $query->where('mac_address', $mac);
})
->get();
if ($fdb->isEmpty()) {
return api_error(404, 'Fdb do not exist');
@@ -2602,6 +2604,36 @@ function del_service_from_host(Illuminate\Http\Request $request)
return api_error(500, 'Failed to delete the service');
}
function search_by_mac(Illuminate\Http\Request $request)
{
$macAddress = Rewrite::macToHex((string) $request->route('search'));
$rules = [
'macAddress' => 'required|string|regex:/^[0-9a-fA-F]{12}$/',
];
$validate = Validator::make(['macAddress' => $macAddress], $rules);
if ($validate->fails()) {
return api_error(422, $validate->messages());
}
$ports = Port::whereHas('fdbEntries', function ($fdbDownlink) use ($macAddress) {
$fdbDownlink->where('mac_address', $macAddress);
})
->withCount('fdbEntries')
->orderBy('fdb_entries_count')
->get();
if ($ports->count() == 0) {
return api_error(404, 'mac not found');
}
if ($request->has('filter') && $request->get('filter') === 'first') {
return api_success($ports->first(), 'ports');
}
return api_success($ports, 'ports');
}
function edit_service_for_host(Illuminate\Http\Request $request)
{
$service_id = $request->route('id');

View File

@@ -117,6 +117,7 @@ Route::group(['prefix' => 'v0', 'namespace' => '\App\Api\Controllers'], function
Route::get('{portid}', 'LegacyApiController@get_port_info')->name('get_port_info');
Route::get('{portid}/ip', 'LegacyApiController@get_port_ip_addresses')->name('get_port_ip_info');
Route::get('search/{search}', 'LegacyApiController@search_ports')->name('search_ports');
Route::get('mac/{search}', 'LegacyApiController@search_by_mac')->name('search_mac');
Route::get(null, 'LegacyApiController@get_all_ports')->name('get_all_ports');
});

View File

@@ -0,0 +1,36 @@
<?php
namespace LibreNMS\Tests\Unit\Util;
use LibreNMS\Tests\TestCase;
use LibreNMS\Util\Rewrite;
class RewriteTest extends TestCase
{
/**
* @test
* @dataProvider validMacProvider
*/
public function testMacToHex(string $from, string $to): void
{
$this->assertEquals(Rewrite::macToHex($from), $to);
}
public function validMacProvider(): array
{
return [
['00:00:00:00:00:01', '000000000001'],
['00-00-00-00-00-01', '000000000001'],
['000000.000001', '000000000001'],
['000000000001', '000000000001'],
['00:12:34:ab:cd:ef', '001234abcdef'],
['00:12:34:AB:CD:EF', '001234ABCDEF'],
['0:12:34:AB:CD:EF', '001234ABCDEF'],
['00-12-34-AB-CD-EF', '001234ABCDEF'],
['001234-ABCDEF', '001234ABCDEF'],
['0012.34AB.CDEF', '001234ABCDEF'],
['00:02:04:0B:0D:0F', '0002040B0D0F'],
['0:2:4:B:D:F', '0002040B0D0F'],
];
}
}