Skip to content

Commit c55a9bb

Browse files
dot-mikemurrant
andauthored
Feature: CSV Table export (librenms#17310)
* append bootgrid button for export * Add export route for tables and legacy * add legacy export csv script * Add CSV export functionality to tablecontroller * Add basic CSV export functionality. - Device - Mempools - Ports - Processors - Storage - Sensors * Style CI * Fix download button not appear for legacy table * fix utf-8 BOM output for csv file * export table refactor hostname to use displayName() * filename for legacy export should include timestamp * enable export for inventory * sanitize GET parameters to handle nested arrays in legacy controller * fix sorting and add filtering functionality to export * Style CI * fix: prevent redeclaration of array_map_recursive function * Style CI * Revert legacy support for table export. This reverts commit ddcb6ad 5f8baff f45fd19 c043797 Partially reverts 697cb66 c043797 * Add specific export routes for bootgrid tables * Add table export functionality for more classes - Outages - Processors - Sensors - Storage * Add support for pagination. Fix Filtering * Revert adding DeviceCache to SensorCommon This is a legacy table. * Style CI * preferred route format --------- Co-authored-by: Tony Murray <[email protected]>
1 parent 422c3ae commit c55a9bb

19 files changed

+725
-103
lines changed

app/Http/Controllers/Table/DeviceController.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,4 +358,60 @@ private function getActions(Device $device): array
358358

359359
return $actions;
360360
}
361+
362+
/**
363+
* Get headers for CSV export
364+
*
365+
* @return array
366+
*/
367+
protected function getExportHeaders()
368+
{
369+
return [
370+
'Device ID',
371+
'Hostname',
372+
'IP Address',
373+
'Hardware',
374+
'OS',
375+
'Version',
376+
'Features',
377+
'Location',
378+
'Uptime',
379+
'Status',
380+
'Type',
381+
'Last Polled',
382+
];
383+
}
384+
385+
/**
386+
* Format a row for CSV export
387+
*
388+
* @param Device $device
389+
* @return array
390+
*/
391+
protected function formatExportRow($device)
392+
{
393+
$status = $device->status ? 'Up' : 'Down';
394+
if ($device->disabled) {
395+
$status = 'Disabled';
396+
} elseif ($device->ignore) {
397+
$status = 'Ignored';
398+
}
399+
400+
$location = $device->location ? $device->location->location : '';
401+
402+
return [
403+
'device_id' => $device->device_id,
404+
'hostname' => $device->displayName(),
405+
'ip' => $device->ip,
406+
'hardware' => Rewrite::ciscoHardware($device),
407+
'os' => Config::getOsSetting($device->os, 'text', $device->os),
408+
'version' => $device->version,
409+
'features' => $device->features,
410+
'location' => $location,
411+
'uptime' => $device->status ? Time::formatInterval($device->uptime, true) : 'Down',
412+
'status' => $status,
413+
'type' => $device->type,
414+
'last_polled' => $device->last_polled,
415+
];
416+
}
361417
}

app/Http/Controllers/Table/InventoryController.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
class InventoryController extends TableController
3535
{
36+
protected $model = EntPhysical::class;
37+
3638
public function rules()
3739
{
3840
return [
@@ -94,4 +96,37 @@ public function formatItem($entPhysical)
9496
'serial' => htmlspecialchars($entPhysical->entPhysicalSerialNum),
9597
];
9698
}
99+
100+
/**
101+
* Get headers for CSV export
102+
*
103+
* @return array
104+
*/
105+
protected function getExportHeaders()
106+
{
107+
return [
108+
'Device',
109+
'Description',
110+
'Name',
111+
'Model',
112+
'Serial Number',
113+
];
114+
}
115+
116+
/**
117+
* Format a row for CSV export
118+
*
119+
* @param EntPhysical $entPhysical
120+
* @return array
121+
*/
122+
protected function formatExportRow($entPhysical)
123+
{
124+
return [
125+
$entPhysical->device ? $entPhysical->device->displayName() : '',
126+
$entPhysical->entPhysicalDescr,
127+
$entPhysical->entPhysicalName,
128+
$entPhysical->entPhysicalModelName,
129+
$entPhysical->entPhysicalSerialNum,
130+
];
131+
}
97132
}

app/Http/Controllers/Table/MempoolsController.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,45 @@ private function barLink(Mempool $mempool)
136136

137137
return Url::overlibLink($link, $percent, Url::graphTag($graph));
138138
}
139+
140+
/**
141+
* Get headers for CSV export
142+
*
143+
* @return array
144+
*/
145+
protected function getExportHeaders()
146+
{
147+
return [
148+
'Device ID',
149+
'Hostname',
150+
'Description',
151+
'Used',
152+
'Free',
153+
'Total',
154+
'Percentage',
155+
'Warning Threshold',
156+
];
157+
}
158+
159+
/**
160+
* Format a row for CSV export
161+
*
162+
* @param Mempool $mempool
163+
* @return array
164+
*/
165+
protected function formatExportRow($mempool)
166+
{
167+
$is_percent = $mempool->mempool_total == 100;
168+
169+
return [
170+
'device_id' => $mempool->device_id,
171+
'hostname' => $mempool->device->displayName(),
172+
'description' => $mempool->mempool_descr,
173+
'used' => $is_percent ? $mempool->mempool_used : Number::formatBi($mempool->mempool_used),
174+
'free' => $is_percent ? $mempool->mempool_free : Number::formatBi($mempool->mempool_free),
175+
'total' => $is_percent ? $mempool->mempool_total : Number::formatBi($mempool->mempool_total),
176+
'percentage' => $mempool->mempool_perc . '%',
177+
'warning_threshold' => $mempool->mempool_perc_warn ?? '-',
178+
];
179+
}
139180
}

app/Http/Controllers/Table/OutagesController.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
class OutagesController extends TableController
3535
{
36+
protected $model = DeviceOutage::class;
37+
3638
public function rules()
3739
{
3840
return [
@@ -132,4 +134,35 @@ private function statusLabel($outage)
132134

133135
return $output;
134136
}
137+
138+
/**
139+
* Get headers for CSV export
140+
*
141+
* @return array
142+
*/
143+
protected function getExportHeaders()
144+
{
145+
return [
146+
'Device Hostname',
147+
'Start',
148+
'End',
149+
'Duration',
150+
];
151+
}
152+
153+
/**
154+
* Format a row for CSV export
155+
*
156+
* @param DeviceOutage $outage
157+
* @return array
158+
*/
159+
protected function formatExportRow($outage)
160+
{
161+
return [
162+
$outage->device ? $outage->device->displayName() : '',
163+
$this->formatDatetime($outage->going_down),
164+
$outage->up_again ? $this->formatDatetime($outage->up_again) : '-',
165+
$this->formatTime(($outage->up_again ?: time()) - $outage->going_down),
166+
];
167+
}
135168
}

app/Http/Controllers/Table/PortsController.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,67 @@ public function formatItem($port)
173173
'actions' => (string) view('port.actions', ['port' => $port]),
174174
];
175175
}
176+
177+
/**
178+
* Get headers for CSV export
179+
*
180+
* @return array
181+
*/
182+
protected function getExportHeaders()
183+
{
184+
return [
185+
'Device ID',
186+
'Hostname',
187+
'Port',
188+
'ifIndex',
189+
'Status',
190+
'Admin Status',
191+
'Speed',
192+
'MTU',
193+
'Type',
194+
'In Rate (bps)',
195+
'Out Rate (bps)',
196+
'In Errors',
197+
'Out Errors',
198+
'In Error Rate',
199+
'Out Error Rate',
200+
'Description',
201+
'Last Change',
202+
'Connector Present',
203+
];
204+
}
205+
206+
/**
207+
* Format a row for CSV export
208+
*
209+
* @param Port $port
210+
* @return array
211+
*/
212+
protected function formatExportRow($port)
213+
{
214+
$status = $port->ifOperStatus;
215+
$adminStatus = $port->ifAdminStatus;
216+
$speed = Number::formatSi($port->ifSpeed);
217+
218+
return [
219+
'device_id' => $port->device_id,
220+
'hostname' => $port->device->displayName(),
221+
'port' => $port->ifName ?: $port->ifDescr,
222+
'ifindex' => $port->ifIndex,
223+
'status' => $status,
224+
'admin_status' => $adminStatus,
225+
'speed' => $speed,
226+
'mtu' => $port->ifMtu,
227+
'type' => Rewrite::normalizeIfType($port->ifType),
228+
'in_rate' => Number::formatBi($port->ifInOctets_rate * 8) . 'bps',
229+
'out_rate' => Number::formatBi($port->ifOutOctets_rate * 8) . 'bps',
230+
'in_errors' => $port->ifInErrors,
231+
'out_errors' => $port->ifOutErrors,
232+
'in_errors_rate' => $port->poll_period ? Number::formatSi($port->ifInErrors_delta / $port->poll_period, 2, 0, 'EPS') : '',
233+
'out_errors_rate' => $port->poll_period ? Number::formatSi($port->ifOutErrors_delta / $port->poll_period, 2, 0, 'EPS') : '',
234+
'description' => $port->ifAlias,
235+
'last_change' => $port->device ? ($port->device->uptime - ($port->ifLastChange / 100)) : 'N/A',
236+
'connector_present' => ($port->ifConnectorPresent == 'true') ? 'yes' : 'no',
237+
];
238+
}
176239
}

app/Http/Controllers/Table/ProcessorsController.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
class ProcessorsController extends TableController
1313
{
14+
protected $model = Processor::class;
15+
1416
protected $default_sort = ['device_hostname' => 'asc', 'processor_descr' => 'asc'];
1517

1618
protected function sortFields($request): array
@@ -74,4 +76,33 @@ public function formatItem($processor): array
7476
'processor_usage' => $usage,
7577
];
7678
}
79+
80+
/**
81+
* Get headers for CSV export
82+
*
83+
* @return array
84+
*/
85+
protected function getExportHeaders()
86+
{
87+
return [
88+
'Device Hostname',
89+
'Processor',
90+
'Usage',
91+
];
92+
}
93+
94+
/**
95+
* Format a row for CSV export
96+
*
97+
* @param Processor $processor
98+
* @return array
99+
*/
100+
protected function formatExportRow($processor)
101+
{
102+
return [
103+
$processor->device ? $processor->device->displayName() : '',
104+
$processor->processor_descr,
105+
$processor->processor_usage,
106+
];
107+
}
77108
}

app/Http/Controllers/Table/SensorsController.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
class SensorsController extends TableController
1515
{
16+
protected $model = Sensor::class;
17+
1618
protected $default_sort = ['device_hostname' => 'asc', 'sensor_descr' => 'asc'];
1719

1820
protected function rules(): array
@@ -101,4 +103,59 @@ public function formatItem($sensor): array
101103
'sensor_limit' => Html::severityToLabel(Severity::Unknown, $sensor->formatValue('sensor_limit')),
102104
];
103105
}
106+
107+
/**
108+
* Get headers for CSV export
109+
*
110+
* @return array
111+
*/
112+
protected function getExportHeaders()
113+
{
114+
return [
115+
'Device Hostname',
116+
'Sensor',
117+
'Current',
118+
'Limit Low',
119+
'Limit High',
120+
'Sensor Class',
121+
'Sensor Type',
122+
];
123+
}
124+
125+
/**
126+
* Format a row for CSV export
127+
*
128+
* @param Sensor $sensor
129+
* @return array
130+
*/
131+
protected function formatExportRow($sensor)
132+
{
133+
return [
134+
$sensor->device ? $sensor->device->displayName() : '',
135+
$sensor->sensor_descr,
136+
$sensor->formatValue(),
137+
$sensor->formatValue('sensor_limit_low'),
138+
$sensor->formatValue('sensor_limit'),
139+
$sensor->sensor_class,
140+
$sensor->sensor_type,
141+
];
142+
}
143+
144+
/**
145+
* Export data as CSV with sensor class filter
146+
*
147+
* @param Request $request
148+
* @param string|null $class
149+
* @return \Symfony\Component\HttpFoundation\StreamedResponse
150+
*/
151+
public function export(Request $request, $class = null)
152+
{
153+
if ($class) {
154+
$request->merge(['class' => $class]);
155+
}
156+
157+
$this->validate($request, $this->rules());
158+
159+
return parent::export($request);
160+
}
104161
}

0 commit comments

Comments
 (0)