Issues (2963)

Http/Controllers/Widgets/TopDevicesController.php (1 issue)

1
<?php
2
/**
3
 * TopDevices.php
4
 *
5
 * -Description-
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * @link       https://www.librenms.org
21
 *
22
 * @copyright  2018 Tony Murray
23
 * @author     Tony Murray <[email protected]>
24
 */
25
26
namespace App\Http\Controllers\Widgets;
27
28
use App\Models\Device;
29
use App\Models\Mempool;
30
use App\Models\Port;
31
use App\Models\Processor;
32
use App\Models\Storage;
33
use Carbon\Carbon;
34
use Illuminate\Database\Eloquent\Builder;
35
use Illuminate\Http\Request;
36
use Illuminate\Support\Collection;
37
use Illuminate\Support\Facades\Auth;
38
use Illuminate\View\View;
39
use LibreNMS\Util\Html;
40
use LibreNMS\Util\StringHelpers;
41
use LibreNMS\Util\Url;
42
use LibreNMS\Util\Validate;
43
44
class TopDevicesController extends WidgetController
45
{
46
    protected $title = 'Top Devices';
47
    protected $defaults = [
48
        'title' => null,
49
        'top_query' => 'traffic',
50
        'sort_order' => 'desc',
51
        'device_count' => 5,
52
        'time_interval' => 15,
53
        'device_group' => null,
54
    ];
55
56
    public function title()
57
    {
58
        $settings = $this->getSettings();
59
60
        return isset($settings['title']) ? $settings['title'] : $this->title;
61
    }
62
63
    /**
64
     * @param  Request  $request
65
     * @return View
66
     */
67
    public function getView(Request $request)
68
    {
69
        $settings = $this->getSettings();
70
        $sort = $settings['sort_order'];
71
72
        // We use raw() function below, validate input and default to sane value.
73
        $sort = Validate::ascDesc($sort, 'ASC');
74
75
        switch ($settings['top_query']) {
76
            case 'traffic':
77
                $data = $this->getTrafficData($sort);
78
                break;
79
            case 'uptime':
80
                $data = $this->getUptimeData($sort);
81
                break;
82
            case 'ping':
83
                $data = $this->getPingData($sort);
84
                break;
85
            case 'cpu':
86
                $data = $this->getProcessorData($sort);
87
                break;
88
            case 'ram':
89
                $data = $this->getMemoryData($sort);
90
                break;
91
            case 'poller':
92
                $data = $this->getPollerData($sort);
93
                break;
94
            case 'storage':
95
                $data = $this->getStorageData($sort);
96
                break;
97
            default:
98
                $data = [];
99
        }
100
101
        return view('widgets.top-devices', $data);
102
    }
103
104
    public function getSettingsView(Request $request)
105
    {
106
        return view('widgets.settings.top-devices', $this->getSettings(true));
107
    }
108
109
    /**
110
     * @param  array|string  $headers
111
     * @param  Collection  $rows
112
     * @return array
113
     */
114
    private function formatData($headers, $rows)
115
    {
116
        return [
117
            'headers' => (array) $headers,
118
            'rows' => $rows,
119
        ];
120
    }
121
122
    /**
123
     * @param  Builder  $query
124
     * @param  string  $left_table
125
     * @return Builder
126
     */
127
    private function withDeviceQuery(Builder $query, $left_table)
128
    {
129
        $settings = $this->getSettings();
130
131
        /** @var Builder $query */
132
        return $query->with(['device' => function ($query) {
133
            return $query->select('device_id', 'hostname', 'sysName', 'status', 'os');
134
        }])
135
            ->select("$left_table.device_id")
136
            ->leftJoin('devices', "$left_table.device_id", 'devices.device_id')
137
            ->groupBy("$left_table.device_id")
138
            ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval']))
139
            ->when($settings['device_group'], function ($query) use ($settings) {
140
                /** @var Builder<\App\Models\DeviceRelatedModel> $query */
141
                $inDeviceGroup = $query->inDeviceGroup($settings['device_group']); /** @var Builder $inDeviceGroup */
142
143
                return $inDeviceGroup;
144
            });
145
    }
146
147
    /**
148
     * @return Builder
149
     */
150
    private function deviceQuery()
151
    {
152
        $settings = $this->getSettings();
153
154
        return Device::hasAccess(Auth::user())->select('device_id', 'hostname', 'sysName', 'status', 'os')
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Models\Device...ttings['device_count']) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
155
            ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval']))
156
            ->when($settings['device_group'], function ($query) use ($settings) {
157
                return $query->inDeviceGroup($settings['device_group']);
158
            })
159
            ->limit($settings['device_count']);
160
    }
161
162
    /**
163
     * @param  Device  $device
164
     * @param  string  $graph_type
165
     * @param  array  $graph_params
166
     * @return array
167
     */
168
    private function standardRow($device, $graph_type, $graph_params = [])
169
    {
170
        return [
171
            Url::deviceLink($device, $device->shortDisplayName()),
172
            Url::deviceLink($device, Url::minigraphImage(
173
                $device,
174
                Carbon::now()->subDays(1)->timestamp,
175
                Carbon::now()->timestamp,
176
                $graph_type,
177
                'no',
178
                150,
179
                21
180
            ), $graph_params, 0, 0, 0),
181
        ];
182
    }
183
184
    private function getTrafficData($sort)
185
    {
186
        $settings = $this->getSettings();
187
188
        $query = Port::hasAccess(Auth::user())->with(['device' => function ($query) {
189
            $query->select('device_id', 'hostname', 'sysName', 'status', 'os');
190
        }])
191
            ->select('device_id')
192
            ->groupBy('device_id')
193
            ->where('poll_time', '>', Carbon::now()->subMinutes($settings['time_interval'])->timestamp)
194
            ->when($settings['device_group'], function ($query) use ($settings) {
195
                return $query->inDeviceGroup($settings['device_group']);
196
            }, function ($query) {
197
                return $query->has('device');
198
            })
199
            ->orderByRaw('SUM(ifInOctets_rate + ifOutOctets_rate) ' . $sort)
200
            ->limit($settings['device_count']);
201
202
        $results = $query->get()->map(function ($port) {
203
            return $this->standardRow($port->device, 'device_bits');
204
        });
205
206
        return $this->formatData('Traffic', $results);
207
    }
208
209
    private function getUptimeData($sort)
210
    {
211
        $settings = $this->getSettings();
212
213
        /** @var Builder $query */
214
        $query = $this->deviceQuery()->orderBy('uptime', $sort)->limit($settings['device_count']);
215
216
        $results = $query->get()->map(function ($device) {
217
            /** @var Device $device */
218
            return $this->standardRow($device, 'device_uptime', ['tab' => 'graphs', 'group' => 'system']);
219
        });
220
221
        return $this->formatData('Uptime', $results);
222
    }
223
224
    private function getPingData($sort)
225
    {
226
        $settings = $this->getSettings();
227
228
        /** @var Builder $query */
229
        $query = $this->deviceQuery()->orderBy('last_ping_timetaken', $sort)->limit($settings['device_count']);
230
231
        $results = $query->get()->map(function ($device) {
232
            /** @var Device $device */
233
            return $this->standardRow($device, 'device_ping_perf', ['tab' => 'graphs', 'group' => 'poller']);
234
        });
235
236
        return $this->formatData('Response time', $results);
237
    }
238
239
    private function getProcessorData($sort)
240
    {
241
        $settings = $this->getSettings();
242
243
        /** @var Processor $query */
244
        $query = $this->withDeviceQuery(Processor::hasAccess(Auth::user()), (new Processor)->getTable())
245
            ->orderByRaw('AVG(`processor_usage`) ' . $sort)
246
            ->limit($settings['device_count']);
247
248
        $results = $query->get()->map(function ($port) {
249
            return $this->standardRow($port->device, 'device_processor', ['tab' => 'health', 'metric' => 'processor']);
250
        });
251
252
        return $this->formatData('CPU Load', $results);
253
    }
254
255
    private function getMemoryData($sort)
256
    {
257
        $settings = $this->getSettings();
258
259
        /** @var Mempool $query */
260
        $query = $this->withDeviceQuery(Mempool::hasAccess(Auth::user()), (new Mempool)->getTable())
261
            ->orderBy('mempool_perc', $sort)
262
            ->limit($settings['device_count']);
263
264
        $results = $query->get()->map(function ($port) {
265
            return $this->standardRow($port->device, 'device_mempool', ['tab' => 'health', 'metric' => 'mempool']);
266
        });
267
268
        return $this->formatData('Memory usage', $results);
269
    }
270
271
    private function getPollerData($sort)
272
    {
273
        $settings = $this->getSettings();
274
275
        $query = $this->deviceQuery()->orderBy('last_polled_timetaken', $sort)->limit($settings['device_count']);
276
277
        $results = $query->get()->map(function ($device) {
278
            /** @var Device $device */
279
            return $this->standardRow($device, 'device_poller_perf', ['tab' => 'graphs', 'group' => 'poller']);
280
        });
281
282
        return $this->formatData('Poller duration', $results);
283
    }
284
285
    private function getStorageData($sort)
286
    {
287
        $settings = $this->getSettings();
288
289
        $query = Storage::hasAccess(Auth::user())->with(['device' => function ($query) {
290
            $query->select('device_id', 'hostname', 'sysName', 'status', 'os');
291
        }])
292
            ->leftJoin('devices', 'storage.device_id', 'devices.device_id')
293
            ->select('storage.device_id', 'storage_id', 'storage_descr', 'storage_perc', 'storage_perc_warn')
294
            ->where('devices.last_polled', '>', Carbon::now()->subMinutes($settings['time_interval']))
295
            ->when($settings['device_group'], function ($query) use ($settings) {
296
                $query->inDeviceGroup($settings['device_group']);
297
            })
298
            ->orderBy('storage_perc', $sort)
299
            ->limit($settings['device_count']);
300
301
        $results = $query->get()->map(function ($storage) {
302
            $device = $storage->device;
303
304
            $graph_array = [
305
                'height' => 100,
306
                'width' => 210,
307
                'to' => Carbon::now()->timestamp,
308
                'from' => Carbon::now()->subDay()->timestamp,
309
                'id' => $storage->storage_id,
310
                'type' => 'storage_usage',
311
                'legend' => 'no',
312
            ];
313
            $overlib_content = Url::overlibContent($graph_array, $device->displayName() . ' - ' . $storage->storage_descr);
314
315
            $link_array = $graph_array;
316
            $link_array['page'] = 'graphs';
317
            unset($link_array['height'], $link_array['width'], $link_array['legend']);
318
            $link = Url::generate($link_array);
319
320
            return [
321
                Url::deviceLink($device, $device->shortDisplayName()),
322
                StringHelpers::shortenText($storage->storage_descr, 50),
323
                Url::overlibLink(
324
                    $link,
325
                    Html::percentageBar(150, 20, $storage->storage_perc, '', $storage->storage_perc . '%', $storage->storage_perc_warn),
326
                    $overlib_content
327
                ),
328
            ];
329
        });
330
331
        return $this->formatData(['Storage Device', 'Disk usage'], $results);
332
    }
333
}
334