root / plugins / ubiquiti / unifi_api @ c0108c95
Historique | Voir | Annoter | Télécharger (38,3 ko)
| 1 |
#!/usr/bin/perl |
|---|---|
| 2 |
# -*- perl -*- |
| 3 |
|
| 4 |
=encoding utf8 |
| 5 |
|
| 6 |
=head1 NAME |
| 7 |
|
| 8 |
unifi_api - Munin plugin to display device and network information from the |
| 9 |
Ubiquiti unifi API |
| 10 |
|
| 11 |
=head1 APPLICABLE SYSTEMS |
| 12 |
|
| 13 |
Unifi controllors with direct API access |
| 14 |
|
| 15 |
Controller version 5+ required (tested with 5.8.x) |
| 16 |
|
| 17 |
WebRTC is not supported at this time |
| 18 |
|
| 19 |
=head1 CONFIGURATION |
| 20 |
|
| 21 |
This script uses the multigraph functionality to generate many graphs. As such, there |
| 22 |
are a significant amount of available configuration options |
| 23 |
|
| 24 |
=head2 API Details |
| 25 |
|
| 26 |
You will need to supply your API login details: |
| 27 |
|
| 28 |
[unifi_api] |
| 29 |
# User name to login to unifi controller API. Default is "ubnt". Ideally, this should |
| 30 |
# point to a read-only account. |
| 31 |
env.user Controller_Username |
| 32 |
|
| 33 |
# Password to login to unifi controller API. Default is "ubnt" |
| 34 |
env.pass Controller_Password |
| 35 |
|
| 36 |
# URL of the API, with port if needed. No trailing slash. |
| 37 |
# Default is https://localhost:8443 |
| 38 |
env.api_url https://unifi.fqdn.com:8443 |
| 39 |
|
| 40 |
# Verify SSL certificate name against host. |
| 41 |
# Note: if using a default cloudkey certificate, this will fail unless you manually add it |
| 42 |
# to the local keystore. |
| 43 |
# Default is "yes" |
| 44 |
env.ssl_verify_host no |
| 45 |
|
| 46 |
# Verify Peer's SSL vertiicate. |
| 47 |
# Note: if using a default cloudkey certificate, this will fail |
| 48 |
# Default is "yes" |
| 49 |
env.ssl_verify_peer no |
| 50 |
|
| 51 |
# The human readable name of the unifi site - used for graph titles |
| 52 |
env.name Site Name |
| 53 |
|
| 54 |
# "Site" string - the internal unifi API site identifier. |
| 55 |
# default is "default" - found when you connect to the web interface |
| 56 |
# it's the term in the URL - /manage/site/site_string/dashboard |
| 57 |
env.site site_string |
| 58 |
|
| 59 |
|
| 60 |
=head2 Graph Categories / Host Management |
| 61 |
|
| 62 |
Sometimes, you need more control over where the unifi graphs appear. |
| 63 |
|
| 64 |
env.force_category 0 |
| 65 |
# By default, Use standard munin well know categories - |
| 66 |
# system: cpu, mem, load, & uptime |
| 67 |
# network: clients, transfer statistics. |
| 68 |
# |
| 69 |
|
| 70 |
To use this feature, set "force_category" to a text string (i.e. "unifi"). |
| 71 |
|
| 72 |
This is very helpful if your graphs are going to appear inside another host - for instance |
| 73 |
if your munin graphs for that host are monitoring the host the controller is running on, and |
| 74 |
the unifi API instance. |
| 75 |
|
| 76 |
Sometimes however, you want to monitor either an offsite API, or a cloudkey which, at least by |
| 77 |
default, does not run munin-node. In that case, you can actually create a "virtual" munin host to |
| 78 |
display only these graphs (or any combination you like). This is documented in the main munin docs, |
| 79 |
but in a nutshell: |
| 80 |
|
| 81 |
In your munin-node plugin configuration: (Something like: /etc/munin/plugin-conf.d/munin-node) |
| 82 |
|
| 83 |
[unifi_api] |
| 84 |
host_name hostname.whatever.youlike |
| 85 |
env.force_category unifi |
| 86 |
|
| 87 |
And, in your munin master configuration: (Something like: /etc/munin/munin.conf) |
| 88 |
|
| 89 |
[hostname.whatever.youlike] |
| 90 |
address ip.of.munin.node |
| 91 |
|
| 92 |
Make sure you do *not* set "use_node_name" on this new host. It may be necessary to define "host_name" |
| 93 |
in your munin-node configuration as well, if you have not already (Likely, on a multi-homed host, this |
| 94 |
has been done to keep munin-node from advertising itself as localhost) |
| 95 |
|
| 96 |
More information: |
| 97 |
|
| 98 |
* L<host_name|http://guide.munin-monitoring.org/en/latest/plugin/use.html> |
| 99 |
|
| 100 |
|
| 101 |
=head2 Toggling of graphs / Individual options |
| 102 |
|
| 103 |
You can turn off individual graphs. A few graphs have extra configuration |
| 104 |
options. |
| 105 |
|
| 106 |
By default, everything is enabled. Set to "no" to disable |
| 107 |
|
| 108 |
[unifi_api] |
| 109 |
# Show device CPU utilization |
| 110 |
env.enable_device_cpu yes |
| 111 |
|
| 112 |
# Show device memory usage |
| 113 |
env.enable_device_mem yes |
| 114 |
|
| 115 |
# Show device load average (switches and APs only) |
| 116 |
env.enable_device_load yes |
| 117 |
|
| 118 |
# Show device uptime |
| 119 |
env.enable_device_uptime yes |
| 120 |
|
| 121 |
# Show number of clients connected to each device |
| 122 |
env.enable_clients_device yes |
| 123 |
# Show detailed graphs for each device (per device graphs) |
| 124 |
env.enable_detail_clients_device yes |
| 125 |
|
| 126 |
# Show number of clients connected to each network type |
| 127 |
env.enable_clients_type yes |
| 128 |
# Show detailed graphs for each client type (per type graphs) |
| 129 |
env.enable_detail_clients_type yes |
| 130 |
# Show unauthorized / authorized client list |
| 131 |
# if you are not using the guest portal, this is useless |
| 132 |
env.show_authorized_clients_type yes |
| 133 |
|
| 134 |
# Show transfer statistics on switch ports |
| 135 |
env.enable_xfer_port yes |
| 136 |
# Show detailed graphs per switch port |
| 137 |
env.enable_detail_xfer_port yes |
| 138 |
# Hide ports that have no link (When set to no, unplugged ports will transfer 0, not be undefined) |
| 139 |
env.hide_empty_xfer_port yes |
| 140 |
|
| 141 |
# Show transfer statistics per device |
| 142 |
env.enable_xfer_device yes |
| 143 |
# Show detailed graphs for each device |
| 144 |
env.enable_detail_xfer_device yes |
| 145 |
|
| 146 |
# Show transfer statistics per named network |
| 147 |
env.enable_xfer_network yes |
| 148 |
# Show detailed graphs for each named network |
| 149 |
env.enable_detail_xfer_network yes |
| 150 |
|
| 151 |
# Show transfer statistics per radio |
| 152 |
env.enable_xfer_radio yes |
| 153 |
# Show detailed graphs for each radio |
| 154 |
env.enable_detail_xfer_radio yes |
| 155 |
|
| 156 |
|
| 157 |
=head1 CAPABILITIES |
| 158 |
|
| 159 |
This plugin supports L<DIRTYCONFIG|http://guide.munin-monitoring.org/en/latest/plugin/protocol-dirtyconfig.html> |
| 160 |
|
| 161 |
=head1 DEPENDENCIES |
| 162 |
|
| 163 |
This plugin requires munin-multiugraph. |
| 164 |
|
| 165 |
=over |
| 166 |
|
| 167 |
=item WWW::Curl::Easy |
| 168 |
|
| 169 |
Perl extension interface for libcurl |
| 170 |
|
| 171 |
=item JSON |
| 172 |
|
| 173 |
JSON (JavaScript Object Notation) encoder/decoder |
| 174 |
|
| 175 |
=back |
| 176 |
|
| 177 |
=head1 PERFORMANCE CONCERNS |
| 178 |
|
| 179 |
The main performance concern on this is the huge number of graphs that may be |
| 180 |
generated. Using the cron version of munin-graph may hurt a lot. |
| 181 |
|
| 182 |
A bit of a case study: |
| 183 |
|
| 184 |
| My Site | UBNT Demo |
| 185 |
--------------------------------------- |
| 186 |
Devices | 8 | 126 |
| 187 |
AP's | 4 | 118 |
| 188 |
24xSwitch | 1 | 5 |
| 189 |
8xSwitch | 2 | 2 |
| 190 |
Output Bytes | 64,262 | 431,434 |
| 191 |
Output Lines | 1,761 | 14,586 |
| 192 |
Output Graphs | 77 | 530 |
| 193 |
|
| 194 |
So, just note that the growth in the amount of graphed date can be extreme. |
| 195 |
|
| 196 |
|
| 197 |
=head1 LICENSE |
| 198 |
|
| 199 |
Copyright (C) 2018 J.T.Sage (jtsage@gmail.com) |
| 200 |
|
| 201 |
This program is free software: you can redistribute it and/or modify |
| 202 |
it under the terms of the GNU General Public License as published by |
| 203 |
the Free Software Foundation, either version 3 of the License, or |
| 204 |
any later version. |
| 205 |
|
| 206 |
This program is distributed in the hope that it will be useful, |
| 207 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 208 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 209 |
GNU General Public License for more details. |
| 210 |
|
| 211 |
You should have received a copy of the GNU General Public License |
| 212 |
along with this program. If not, see L<http://www.gnu.org/licenses/>. |
| 213 |
|
| 214 |
=head1 MAGIC MARKERS |
| 215 |
|
| 216 |
#%# family=manual |
| 217 |
#%# capabilities= |
| 218 |
|
| 219 |
=cut |
| 220 |
|
| 221 |
use warnings; |
| 222 |
use strict; |
| 223 |
use utf8; |
| 224 |
use Munin::Plugin; |
| 225 |
|
| 226 |
# Check dependencies |
| 227 |
my @errorCode; |
| 228 |
my $me = (split '/', $0)[-1]; |
| 229 |
|
| 230 |
if (! eval {require JSON; JSON->import(); 1; } ) {
|
| 231 |
push @errorCode, "JSON module not found"; |
| 232 |
} |
| 233 |
if (! eval {require WWW::Curl::Easy; 1;} ) {
|
| 234 |
push @errorCode, "WWW::Curl::Easy module not found"; |
| 235 |
} |
| 236 |
|
| 237 |
# Fail on not found dependencies |
| 238 |
if ( @errorCode != 0 ) {
|
| 239 |
die "FATAL:$me: Perl dependencies not installed (", join(", " => @errorCode), ")\n";
|
| 240 |
} |
| 241 |
|
| 242 |
# Multigraph cabability is required for this plugin |
| 243 |
need_multigraph(); |
| 244 |
|
| 245 |
# Somewhat (in)sane defaults for host, pass, etc |
| 246 |
my %APIconfig = ( |
| 247 |
'user' => env_default_text('user' , 'ubnt'),
|
| 248 |
'pass' => env_default_text('pass' , 'ubnt'),
|
| 249 |
'api_url' => env_default_text('api_url' , 'https://localhost:8443'),
|
| 250 |
'site' => env_default_text('site' , 'default'),
|
| 251 |
'ssl_verify_host' => env_default_text('ssl_verify_host', 'yes'),
|
| 252 |
'ssl_verify_peer' => env_default_text('ssl_verify_peer', 'yes'),
|
| 253 |
'name' => env_default_text('name' , 'Unnamed Site'),
|
| 254 |
); |
| 255 |
|
| 256 |
# The big table of plugin options - see POD documentation for what these do. |
| 257 |
my %PluginConfig = ( |
| 258 |
'enable_device_cpu' => env_default_bool_true('enable_device_cpu'),
|
| 259 |
'enable_device_mem' => env_default_bool_true('enable_device_mem'),
|
| 260 |
'enable_device_load' => env_default_bool_true('enable_device_load'),
|
| 261 |
'enable_device_uptime' => env_default_bool_true('enable_device_uptime'),
|
| 262 |
'enable_clients_device' => env_default_bool_true('enable_clients_device'),
|
| 263 |
'enable_clients_type' => env_default_bool_true('enable_clients_network'),
|
| 264 |
'enable_xfer_port' => env_default_bool_true('enable_xfer_port'),
|
| 265 |
'enable_xfer_device' => env_default_bool_true('enable_xfer_device'),
|
| 266 |
'enable_xfer_network' => env_default_bool_true('enable_xfer_network'),
|
| 267 |
'enable_xfer_radio' => env_default_bool_true('enable_xfer_radio'),
|
| 268 |
'enable_detail_xfer_port' => env_default_bool_true('enable_detail_xfer_port'),
|
| 269 |
'enable_detail_xfer_device' => env_default_bool_true('enable_detail_xfer_device'),
|
| 270 |
'enable_detail_xfer_network' => env_default_bool_true('enable_detail_xfer_network'),
|
| 271 |
'enable_detail_xfer_radio' => env_default_bool_true('enable_detail_xfer_radio'),
|
| 272 |
'enable_detail_clients_device' => env_default_bool_true('enable_detail_clients_device'),
|
| 273 |
'enable_detail_clients_type' => env_default_bool_true('enable_detail_clients_network'),
|
| 274 |
'hide_empty_xfer_port' => env_default_bool_true('hide_empty_xfer_port'),
|
| 275 |
'show_authorized_clients_type' => env_default_bool_true('show_authorized_clients_type'),
|
| 276 |
'force_category' => env_default_text('force_category', 0),
|
| 277 |
); |
| 278 |
|
| 279 |
# Set up needed API endpoints |
| 280 |
my %APIPoint = ( |
| 281 |
'login' => $APIconfig{"api_url"} . "/api/login",
|
| 282 |
'device' => $APIconfig{"api_url"} . "/api/s/" . $APIconfig{"site"} . "/stat/device",
|
| 283 |
'wlan' => $APIconfig{"api_url"} . "/api/s/" . $APIconfig{"site"} . "/rest/wlanconf",
|
| 284 |
'sta' => $APIconfig{"api_url"} . "/api/s/" . $APIconfig{"site"} . "/stat/sta",
|
| 285 |
); |
| 286 |
|
| 287 |
my %APIResponse; |
| 288 |
my %APIJsonResponse; |
| 289 |
my %Data; |
| 290 |
my $retcode; |
| 291 |
|
| 292 |
# Init curl and JSON |
| 293 |
my $curl = WWW::Curl::Easy->new() or die "FATAL:$me: WWW::Curl::Easy init failed!\n"; |
| 294 |
my $jsonOBJ = JSON->new() or die "FATAL:$me: JSON init failed!\n"; |
| 295 |
|
| 296 |
|
| 297 |
## Fetch the data from the API |
| 298 |
|
| 299 |
# The rest is a way to use local files from the local disk. Undocumented and not really supported. |
| 300 |
|
| 301 |
if ( !env_default_bool_true('USE_API') ) {
|
| 302 |
if (! eval {require File::Slurp; File::Slurp->import(); 1; } ) {
|
| 303 |
die "Local debug unavailable, File::Slurp CPAN module required\n"; |
| 304 |
} |
| 305 |
foreach ( "./demo-test-files/device", "./demo-test-files/sta", "./demo-test-files/wlanconf" ) {
|
| 306 |
if ( ! -f $_ ) { die "File not found: $_\n"; }
|
| 307 |
} |
| 308 |
$APIJsonResponse{'device'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode(read_file('./demo-test-files/device'));
|
| 309 |
$APIJsonResponse{'sta'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode(read_file('./demo-test-files/sta'));
|
| 310 |
$APIJsonResponse{'wlan'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode(read_file('./demo-test-files/wlanconf'));
|
| 311 |
} else {
|
| 312 |
fetch_data(); |
| 313 |
} |
| 314 |
|
| 315 |
|
| 316 |
## Process the data |
| 317 |
|
| 318 |
make_data(); |
| 319 |
|
| 320 |
if ( defined($ARGV[0]) && $ARGV[0] eq "config" ) {
|
| 321 |
# Do the config step for each set of graphs |
| 322 |
do_config_mem(); |
| 323 |
do_config_cpu(); |
| 324 |
do_config_load(); |
| 325 |
do_config_uptime(); |
| 326 |
do_config_xfer_by_device(); |
| 327 |
do_config_xfer_by_uplink(); |
| 328 |
do_config_xfer_by_port(); |
| 329 |
do_config_xfer_by_network(); |
| 330 |
do_config_xfer_by_radio(); |
| 331 |
do_config_clients_by_device(); |
| 332 |
do_config_clients_by_type(); |
| 333 |
|
| 334 |
# If dirtyconfig is not supported, or turned off, exit here. Otherwise, continue to fetch section |
| 335 |
if ( !defined($ENV{'MUNIN_CAP_DIRTYCONFIG'}) || !$ENV{'MUNIN_CAP_DIRTYCONFIG'} ) { exit 0; }
|
| 336 |
} |
| 337 |
|
| 338 |
# Do the fetch step for each set of graphs |
| 339 |
do_values_cpu(); |
| 340 |
do_values_mem(); |
| 341 |
do_values_load(); |
| 342 |
do_values_uptime(); |
| 343 |
do_values_xfer_by_device(); |
| 344 |
do_values_xfer_by_uplink(); |
| 345 |
do_values_xfer_by_port(); |
| 346 |
do_values_xfer_by_network(); |
| 347 |
do_values_xfer_by_radio(); |
| 348 |
do_values_clients_by_device(); |
| 349 |
do_values_clients_by_type(); |
| 350 |
|
| 351 |
|
| 352 |
|
| 353 |
|
| 354 |
|
| 355 |
|
| 356 |
|
| 357 |
####################### |
| 358 |
# SUBROUTINES CONFIG # |
| 359 |
####################### |
| 360 |
|
| 361 |
sub do_config_clients_by_type {
|
| 362 |
# Provide client count by type - CONFIG |
| 363 |
if ( !$PluginConfig{'enable_clients_type'} ) { return 0; }
|
| 364 |
|
| 365 |
graph_prologue( |
| 366 |
'unifi_clients_per_network', |
| 367 |
'Clients Connected / Network', |
| 368 |
'-l 0 --base 1000', |
| 369 |
'clients', |
| 370 |
'network', |
| 371 |
'Clients connected per type - manually summing these numbers may be meaningful, as clients are often of multiple types' |
| 372 |
); |
| 373 |
|
| 374 |
foreach ( @{$Data{'typesOrder'}} ) {
|
| 375 |
print $_ , ".label " , $Data{'types'}{$_}[0] , "\n";
|
| 376 |
} |
| 377 |
|
| 378 |
if ( ! $PluginConfig{'enable_detail_clients_type'} ) { return 1; }
|
| 379 |
|
| 380 |
foreach ( @{$Data{'typesOrder'}} ) {
|
| 381 |
if ( $Data{'types'}{$_}[1] == 1 ) {
|
| 382 |
graph_prologue( |
| 383 |
'unifi_clients_per_network.' . $_, |
| 384 |
'Clients Connected : ' . $Data{'types'}{$_}[0],
|
| 385 |
'-l 0 --base 1000', |
| 386 |
'clients', |
| 387 |
'network', |
| 388 |
'Clients connected via that are of type: ' . $Data{'types'}{$_}[0]
|
| 389 |
); |
| 390 |
print "users.label Users\n"; |
| 391 |
print "guests.label Guests\n"; |
| 392 |
} |
| 393 |
} |
| 394 |
return 1; |
| 395 |
} |
| 396 |
|
| 397 |
sub do_config_clients_by_device {
|
| 398 |
# Provide client count by device - CONFIG |
| 399 |
if ( !$PluginConfig{'enable_clients_device'} ) { return 0; }
|
| 400 |
|
| 401 |
graph_prologue( |
| 402 |
'unifi_clients_per_device', |
| 403 |
'Clients Connected / Device', |
| 404 |
'-l 0 --base 1000', |
| 405 |
'clients', |
| 406 |
'network', |
| 407 |
'Clients connected to each unifi device' |
| 408 |
); |
| 409 |
|
| 410 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 411 |
print $_ , ".label " , $Data{'device'}{$_}->{'label'} , "\n";
|
| 412 |
} |
| 413 |
|
| 414 |
if ( ! $PluginConfig{'enable_detail_clients_device'} ) { return 1; }
|
| 415 |
|
| 416 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 417 |
graph_prologue( |
| 418 |
'unifi_clients_per_device.' . $_, |
| 419 |
'Clients / Device : ' . $Data{'device'}{$_}->{'label'},
|
| 420 |
'-l 0 --base 1000', |
| 421 |
'clients', |
| 422 |
'network', |
| 423 |
'Clients connected to the ' . $Data{'device'}{$_}->{'label'} . " unifi device"
|
| 424 |
); |
| 425 |
print "users.label Users\n"; |
| 426 |
print "guests.label Guests\n"; |
| 427 |
} |
| 428 |
return 1; |
| 429 |
} |
| 430 |
|
| 431 |
sub do_config_xfer_by_radio {
|
| 432 |
# Provide transfer for radios - CONFIG |
| 433 |
if ( !$PluginConfig{'enable_xfer_radio'} ) { return 0; }
|
| 434 |
|
| 435 |
graph_prologue( |
| 436 |
'unifi_xfer_per_radio', |
| 437 |
'Transfer / radio', |
| 438 |
'--base 1000', |
| 439 |
'Packets/${graph_period}',
|
| 440 |
'network', |
| 441 |
'Number of packets transferred per individual radio band' |
| 442 |
); |
| 443 |
|
| 444 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 445 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "uap" ) { next; }
|
| 446 |
|
| 447 |
foreach ( @{$Data{'device'}{$thisDevice}{'radio'}} ) {
|
| 448 |
print $thisDevice , "_" , $_->{"name"} , "_pack.label " , $_->{"label"} , "\n";
|
| 449 |
print $thisDevice , "_" , $_->{"name"} , "_pack.type DERIVE\n";
|
| 450 |
print $thisDevice , "_" , $_->{"name"} , "_pack.min 0\n";
|
| 451 |
} |
| 452 |
} |
| 453 |
|
| 454 |
if ( ! $PluginConfig{'enable_detail_xfer_radio'} ) { return 1; }
|
| 455 |
|
| 456 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 457 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "uap" ) { next; }
|
| 458 |
|
| 459 |
graph_prologue( |
| 460 |
'unifi_xfer_per_radio.' . $thisDevice, |
| 461 |
'Transfer / radio : ' . $Data{'device'}{$thisDevice}->{'name'},
|
| 462 |
'--base 1000', |
| 463 |
'Packets/${graph_period}',
|
| 464 |
'network', |
| 465 |
'Transfered Packets, Dropped / Retried Packets, and Error Packets for the WLAN device: ' . $Data{'device'}{$thisDevice}->{'name'}
|
| 466 |
); |
| 467 |
|
| 468 |
foreach ( @{$Data{'device'}{$thisDevice}{'radio'}} ) {
|
| 469 |
print $_->{"name"} , "_pkt.label " , $_->{"type"} , " Packets\n";
|
| 470 |
print $_->{"name"} , "_pkt.type DERIVE\n";
|
| 471 |
print $_->{"name"} , "_pkt.min 0\n";
|
| 472 |
print $_->{"name"} , "_dret.label " , $_->{"type"} , " Dropped / Retries\n";
|
| 473 |
print $_->{"name"} , "_dret.type DERIVE\n";
|
| 474 |
print $_->{"name"} , "_dret.min 0\n";
|
| 475 |
print $_->{"name"} , "_err.label " , $_->{"type"} , " Errors\n";
|
| 476 |
print $_->{"name"} , "_err.type DERIVE\n";
|
| 477 |
print $_->{"name"} , "_err.min 0\n";
|
| 478 |
} |
| 479 |
} |
| 480 |
return 1; |
| 481 |
} |
| 482 |
|
| 483 |
sub do_config_xfer_by_network {
|
| 484 |
# Provide transfer for named networks - CONFIG |
| 485 |
if ( !$PluginConfig{'enable_xfer_network'} ) { return 0; }
|
| 486 |
|
| 487 |
graph_prologue( |
| 488 |
'unifi_xfer_per_network', |
| 489 |
'Transfer / named network', |
| 490 |
'--base 1000', |
| 491 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 492 |
'network', |
| 493 |
'Bytes sent and received per each named network' |
| 494 |
); |
| 495 |
|
| 496 |
foreach my $thisNet ( sort keys %{$Data{'networks'}} ) {
|
| 497 |
foreach ( "_rxbytes", "_txbytes" ) {
|
| 498 |
print $thisNet , $_ , ".label " , $Data{'networks'}{$thisNet}->{"label"} . "\n";
|
| 499 |
print $thisNet , $_ , ".type DERIVE\n"; |
| 500 |
print $thisNet , $_ , ".min 0\n"; |
| 501 |
} |
| 502 |
print $thisNet , "_rxbytes.graph no\n"; |
| 503 |
print $thisNet , "_txbytes.negative " , $thisNet , "_rxbytes\n"; |
| 504 |
} |
| 505 |
|
| 506 |
if ( ! $PluginConfig{'enable_detail_xfer_network'} ) { return 1; }
|
| 507 |
|
| 508 |
foreach my $thisNet ( sort keys %{$Data{'networks'}} ) {
|
| 509 |
graph_prologue( |
| 510 |
'unifi_xfer_per_network.' . $thisNet, |
| 511 |
'Transfer / named network : ' . $Data{'networks'}{$thisNet}->{'label'},
|
| 512 |
'--base 1000', |
| 513 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 514 |
'network', |
| 515 |
'Bytes sent and received for the network named: ' . $Data{'networks'}{$thisNet}->{'label'}
|
| 516 |
); |
| 517 |
foreach ( "rxbyte", "txbyte" ) {
|
| 518 |
print $_ , ".label Bytes\n"; |
| 519 |
print $_ , ".type DERIVE\n"; |
| 520 |
print $_ , ".min 0\n"; |
| 521 |
} |
| 522 |
print "rxbyte.graph no\n"; |
| 523 |
print "txbyte.negative rxbyte\n"; |
| 524 |
} |
| 525 |
return 1; |
| 526 |
} |
| 527 |
|
| 528 |
sub do_config_xfer_by_port {
|
| 529 |
# Provide transfer for switch ports - CONFIG |
| 530 |
if ( !$PluginConfig{'enable_xfer_port'} ) { return 0; }
|
| 531 |
|
| 532 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 533 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "usw" ) { next; }
|
| 534 |
graph_prologue( |
| 535 |
'unifi_xfer_per_port_' . $thisDevice, |
| 536 |
'Transfer / port : ' . $Data{'device'}{$thisDevice}->{'label'},
|
| 537 |
'--base 1000', |
| 538 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 539 |
'network', |
| 540 |
'Bytes sent and received per port on the switch named: ' . $Data{'device'}{$thisDevice}->{'label'}
|
| 541 |
); |
| 542 |
foreach my $thisPort ( @{$Data{'device'}{$thisDevice}{'ports'}} ) {
|
| 543 |
foreach ( "_rxbytes", "_txbytes" ) {
|
| 544 |
print $thisDevice , "_" , $thisPort->{"name"} , $_ , ".label " , $thisPort->{"label"} . "\n";
|
| 545 |
print $thisDevice , "_" , $thisPort->{"name"} , $_ , ".type DERIVE\n";
|
| 546 |
print $thisDevice , "_" , $thisPort->{"name"} , $_ , ".min 0\n";
|
| 547 |
} |
| 548 |
print $thisDevice , "_" , $thisPort->{"name"} , "_rxbytes.graph no\n";
|
| 549 |
print $thisDevice , "_" , $thisPort->{"name"} , "_txbytes.negative " , $thisDevice , "_" , $thisPort->{"name"} , "_rxbytes\n";
|
| 550 |
} |
| 551 |
} |
| 552 |
|
| 553 |
if ( ! $PluginConfig{'enable_detail_xfer_port'} ) { return 1; }
|
| 554 |
|
| 555 |
# Extended graphs |
| 556 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 557 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "usw" ) { next; }
|
| 558 |
foreach my $thisPort ( @{$Data{'device'}{$thisDevice}{'ports'}} ) {
|
| 559 |
graph_prologue( |
| 560 |
'unifi_xfer_per_port_' . $thisDevice . "." . $thisPort->{'name'},
|
| 561 |
'Transfer / port : ' . $Data{'device'}{$thisDevice}->{'label'} . " : " . $thisPort->{'label'},
|
| 562 |
'--base 1000', |
| 563 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 564 |
'network', |
| 565 |
'Bytes sent and received on port "' . $thisPort->{'label'} . '" of the switch "' . $Data{'device'}{$thisDevice}->{'label'} . '"'
|
| 566 |
); |
| 567 |
foreach ( "rxbyte", "txbyte" ) {
|
| 568 |
print $_ . ".label Bytes\n"; |
| 569 |
print $_ . ".type DERIVE\n"; |
| 570 |
print $_ . ".min 0\n"; |
| 571 |
} |
| 572 |
print "rxbyte.graph no\n"; |
| 573 |
print "txbyte.negative rxbyte\n"; |
| 574 |
} |
| 575 |
} |
| 576 |
return 1; |
| 577 |
} |
| 578 |
|
| 579 |
sub do_config_xfer_by_uplink {
|
| 580 |
# Provide transfer for unifi uplink - CONFIG |
| 581 |
if ( !$PluginConfig{'enable_xfer_device'} ) { return 0; }
|
| 582 |
|
| 583 |
graph_prologue( |
| 584 |
'unifi_xfer_by_uplink', |
| 585 |
'Transfer on uplink : ' . $Data{'uplink'}{'devName'},
|
| 586 |
'--base 1000', |
| 587 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 588 |
'network', |
| 589 |
'Bytes sent and received on the WAN port of the USG, and the speedtest result of the same port' |
| 590 |
); |
| 591 |
|
| 592 |
foreach ( "rx", "tx" ) {
|
| 593 |
print $_ , "_speed.label Speedtest\n"; |
| 594 |
print $_ , "_bytes.label Transferred\n"; |
| 595 |
print $_ , "_speed.type GAUGE\n"; |
| 596 |
print $_ , "_bytes.type DERIVE\n"; |
| 597 |
print $_ , "_speed.min 0\n"; |
| 598 |
print $_ , "_bytes.min 0\n"; |
| 599 |
} |
| 600 |
|
| 601 |
print "rx_speed.graph no\n"; |
| 602 |
print "rx_bytes.graph no\n"; |
| 603 |
print "tx_speed.negative rx_speed\n"; |
| 604 |
print "tx_bytes.negative rx_bytes\n"; |
| 605 |
|
| 606 |
return 1; |
| 607 |
} |
| 608 |
|
| 609 |
sub do_config_xfer_by_device {
|
| 610 |
# Provide transfer for each unifi device - CONFIG |
| 611 |
if ( !$PluginConfig{'enable_xfer_device'} ) { return 0; }
|
| 612 |
|
| 613 |
graph_prologue( |
| 614 |
'unifi_xfer_per_device', |
| 615 |
'Transfer / device', |
| 616 |
'--base 1000', |
| 617 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 618 |
'network', |
| 619 |
'Bytes sent and received per unifi device' |
| 620 |
); |
| 621 |
|
| 622 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 623 |
foreach ( "_rxbytes", "_txbytes" ) {
|
| 624 |
print $thisDevice , $_ , ".label " , $Data{'device'}{$thisDevice}->{'label'} , "\n";
|
| 625 |
print $thisDevice , $_ , ".type DERIVE\n"; |
| 626 |
print $thisDevice , $_ , ".min 0\n"; |
| 627 |
} |
| 628 |
print $thisDevice , "_rxbytes.graph no\n"; |
| 629 |
print $thisDevice , "_txbytes.negative " , $thisDevice , "_rxbytes\n"; |
| 630 |
} |
| 631 |
|
| 632 |
if ( $PluginConfig{'enable_detail_xfer_device'} ) {
|
| 633 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 634 |
graph_prologue( |
| 635 |
'unifi_xfer_per_device.' . $thisDevice, |
| 636 |
'Transfer / device : ' . $Data{'device'}{$thisDevice}->{'label'},
|
| 637 |
'--base 1000', |
| 638 |
'Bytes/${graph_period} rcvd (-) / trans (+)',
|
| 639 |
'network', |
| 640 |
'Bytes sent and received on the unifi device named: ' . $Data{'device'}{$thisDevice}->{'label'}
|
| 641 |
); |
| 642 |
foreach ( "rxbyte", "txbyte" ) {
|
| 643 |
print $_ , ".label Bytes\n"; |
| 644 |
print $_ , ".type DERIVE\n"; |
| 645 |
print $_ , ".min 0\n"; |
| 646 |
} |
| 647 |
print "rxbyte.graph no\n"; |
| 648 |
print "txbyte.negative rxbyte\n"; |
| 649 |
} |
| 650 |
} |
| 651 |
return 1; |
| 652 |
} |
| 653 |
|
| 654 |
sub do_config_uptime {
|
| 655 |
# Provide device uptime for each unifi device - CONFIG |
| 656 |
if ( !$PluginConfig{'enable_device_uptime'} ) { return 0; }
|
| 657 |
graph_prologue( |
| 658 |
'unifi_device_uptime', |
| 659 |
'Uptime', |
| 660 |
'--base 1000 -r --lower-limit 0', |
| 661 |
'days', |
| 662 |
'system', |
| 663 |
'Uptime in days for each unifi device' |
| 664 |
); |
| 665 |
|
| 666 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 667 |
print $_ , ".label " , $Data{'device'}{$_}->{"name"} , "\n";
|
| 668 |
} |
| 669 |
return 1; |
| 670 |
} |
| 671 |
|
| 672 |
sub do_config_cpu {
|
| 673 |
# Provide device CPU usage for each unifi device - CONFIG |
| 674 |
if ( !$PluginConfig{'enable_device_cpu'} ) { return 0; }
|
| 675 |
graph_prologue( |
| 676 |
'unifi_device_cpu', |
| 677 |
'CPU Usage', |
| 678 |
'--base 1000 -r --lower-limit 0 --upper-limit 100', |
| 679 |
'%', |
| 680 |
'system', |
| 681 |
'CPU usage as a percentage for each unifi device' |
| 682 |
); |
| 683 |
|
| 684 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 685 |
print $_ , ".label " , $Data{'device'}{$_}->{"name"} , "\n";
|
| 686 |
} |
| 687 |
return 1; |
| 688 |
} |
| 689 |
|
| 690 |
sub do_config_load {
|
| 691 |
# Provide device load average for each unifi device - CONFIG |
| 692 |
if ( !$PluginConfig{'enable_device_load'} ) { return 0; }
|
| 693 |
graph_prologue( |
| 694 |
'unifi_device_load', |
| 695 |
'Load Average', |
| 696 |
'-l 0 --base 1000', |
| 697 |
'load', |
| 698 |
'system', |
| 699 |
'Load average for each unifi Access Point or Switch' |
| 700 |
); |
| 701 |
|
| 702 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 703 |
if ( $Data{'device'}{$_}->{'type'} eq 'ugw' ) { next; }
|
| 704 |
print $_ , ".label " , $Data{'device'}{$_}->{"name"} , "\n";
|
| 705 |
} |
| 706 |
return 1; |
| 707 |
} |
| 708 |
|
| 709 |
sub do_config_mem {
|
| 710 |
# Provide device memory usage for each unifi device - CONFIG |
| 711 |
if ( !$PluginConfig{'enable_device_mem'} ) { return 0; }
|
| 712 |
graph_prologue( |
| 713 |
'unifi_device_mem', |
| 714 |
'Memory Usage', |
| 715 |
'--base 1000 -r --lower-limit 0 --upper-limit 100', |
| 716 |
'%', |
| 717 |
'system', |
| 718 |
'Memory usage as a percentage for each unifi device' |
| 719 |
); |
| 720 |
|
| 721 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 722 |
print $_ , ".label " , $Data{'device'}{$_}->{"name"} , "\n";
|
| 723 |
} |
| 724 |
return 1; |
| 725 |
} |
| 726 |
|
| 727 |
|
| 728 |
|
| 729 |
|
| 730 |
|
| 731 |
|
| 732 |
|
| 733 |
|
| 734 |
|
| 735 |
|
| 736 |
######################### |
| 737 |
# SUBROUTINES VALUES # |
| 738 |
######################### |
| 739 |
|
| 740 |
sub do_values_clients_by_type {
|
| 741 |
# Provide client count by type - VALUES |
| 742 |
if ( !$PluginConfig{'enable_clients_type'} ) { return 0; }
|
| 743 |
|
| 744 |
print "multigraph unifi_clients_per_network\n"; |
| 745 |
|
| 746 |
foreach ( @{$Data{'typesOrder'}} ) {
|
| 747 |
print $_ , ".value " , ( $Data{'types'}{$_}[2] + $Data{'types'}{$_}[3] ) , "\n";
|
| 748 |
} |
| 749 |
|
| 750 |
if ( ! $PluginConfig{'enable_detail_clients_type'} ) { return 1; }
|
| 751 |
|
| 752 |
foreach ( @{$Data{'typesOrder'}} ) {
|
| 753 |
if ( $Data{'types'}{$_}[1] == 1 ) {
|
| 754 |
print "multigraph unifi_clients_per_network.$_\n"; |
| 755 |
print "users.value " , $Data{'types'}{$_}[2] , "\n";
|
| 756 |
print "guests.value " , $Data{'types'}{$_}[3] , "\n";
|
| 757 |
} |
| 758 |
} |
| 759 |
return 1; |
| 760 |
} |
| 761 |
|
| 762 |
sub do_values_clients_by_device {
|
| 763 |
# Provide client count by device - VALUES |
| 764 |
if ( !$PluginConfig{'enable_clients_device'} ) { return 0; }
|
| 765 |
|
| 766 |
print "multigraph unifi_clients_per_device\n"; |
| 767 |
|
| 768 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 769 |
print $_ , ".value " , $Data{'device'}{$_}->{'clients'} , "\n";
|
| 770 |
} |
| 771 |
|
| 772 |
if ( ! $PluginConfig{'enable_detail_clients_device'} ) { return 1; }
|
| 773 |
|
| 774 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 775 |
print "multigraph unifi_clients_per_device.$_\n"; |
| 776 |
print "users.value " , $Data{'device'}{$_}->{'users'} , "\n";
|
| 777 |
print "guests.value " , $Data{'device'}{$_}->{'guests'} , "\n";
|
| 778 |
} |
| 779 |
return 1; |
| 780 |
} |
| 781 |
|
| 782 |
sub do_values_xfer_by_radio {
|
| 783 |
# Provide transfer for radios - VALUES |
| 784 |
if ( !$PluginConfig{'enable_xfer_radio'} ) { return 0; }
|
| 785 |
|
| 786 |
print "multigraph unifi_xfer_per_radio\n"; |
| 787 |
|
| 788 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 789 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "uap" ) { next; }
|
| 790 |
|
| 791 |
foreach ( @{$Data{'device'}{$thisDevice}{'radio'}} ) {
|
| 792 |
print $thisDevice , "_" , $_->{"name"} , "_pack.value " , ($_->{"pckt"} // 0), "\n";;
|
| 793 |
} |
| 794 |
} |
| 795 |
|
| 796 |
if ( ! $PluginConfig{'enable_detail_xfer_radio'} ) { return 1; }
|
| 797 |
|
| 798 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 799 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "uap" ) { next; }
|
| 800 |
|
| 801 |
print "multigraph unifi_xfer_per_radio.$thisDevice\n"; |
| 802 |
|
| 803 |
foreach ( @{$Data{'device'}{$thisDevice}{'radio'}} ) {
|
| 804 |
print $_->{"name"} , "_pkt.value " , ($_->{"pckt"} // 0) , "\n";
|
| 805 |
print $_->{"name"} , "_dret.value " , ($_->{"dret"} // 0) , "\n";
|
| 806 |
print $_->{"name"} , "_err.value " , ($_->{"err"} // 0) , "\n";
|
| 807 |
} |
| 808 |
} |
| 809 |
return 1; |
| 810 |
} |
| 811 |
|
| 812 |
sub do_values_xfer_by_network {
|
| 813 |
# Provide transfer for named networks - CONFIG |
| 814 |
if ( !$PluginConfig{'enable_xfer_network'} ) { return 0; }
|
| 815 |
|
| 816 |
print "multigraph unifi_xfer_per_network\n"; |
| 817 |
|
| 818 |
foreach my $thisNet ( sort keys %{$Data{'networks'}} ) {
|
| 819 |
print $thisNet , "_rxbytes.value " , ($Data{'networks'}{$thisNet}->{"rx"} // 0) , "\n";
|
| 820 |
print $thisNet , "_txbytes.value " , ($Data{'networks'}{$thisNet}->{"tx"} // 0) , "\n";
|
| 821 |
} |
| 822 |
|
| 823 |
if ( ! $PluginConfig{'enable_detail_xfer_network'} ) { return 1; }
|
| 824 |
|
| 825 |
foreach my $thisNet ( sort keys %{$Data{'networks'}} ) {
|
| 826 |
print "multigraph unifi_xfer_per_network.$thisNet\n"; |
| 827 |
print "rxbyte.value " , ($Data{'networks'}{$thisNet}->{"rx"} // 0) , "\n";
|
| 828 |
print "txbyte.value " , ($Data{'networks'}{$thisNet}->{"tx"} // 0) , "\n";
|
| 829 |
} |
| 830 |
return 1; |
| 831 |
} |
| 832 |
|
| 833 |
sub do_values_xfer_by_port {
|
| 834 |
# Provide transfer for switch ports - VALUES |
| 835 |
if ( !$PluginConfig{'enable_xfer_port'} ) { return 0; }
|
| 836 |
|
| 837 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 838 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "usw" ) { next; }
|
| 839 |
print "multigraph unifi_xfer_per_port_$thisDevice\n"; |
| 840 |
|
| 841 |
foreach ( @{$Data{'device'}{$thisDevice}{'ports'}} ) {
|
| 842 |
print $thisDevice , "_" , $_->{"name"} , "_rxbytes.value " , $_->{"rx"} , "\n";
|
| 843 |
print $thisDevice , "_" , $_->{"name"} , "_txbytes.value " , $_->{"tx"} , "\n";
|
| 844 |
} |
| 845 |
} |
| 846 |
|
| 847 |
if ( ! $PluginConfig{'enable_detail_xfer_port'} ) { return 1; }
|
| 848 |
|
| 849 |
# Extended graphs |
| 850 |
foreach my $thisDevice ( sort keys %{$Data{'device'}} ) {
|
| 851 |
if ( $Data{'device'}{$thisDevice}->{'type'} ne "usw" ) { next; }
|
| 852 |
foreach ( @{$Data{'device'}{$thisDevice}{'ports'}} ) {
|
| 853 |
print 'multigraph unifi_xfer_per_port_' . $thisDevice . "." . $_->{'name'} . "\n";
|
| 854 |
print "rxbyte.value " , $_->{"rx"} , "\n";
|
| 855 |
print "txbyte.value " , $_->{"tx"} , "\n";
|
| 856 |
} |
| 857 |
} |
| 858 |
return 1; |
| 859 |
} |
| 860 |
|
| 861 |
sub do_values_xfer_by_uplink {
|
| 862 |
# Provide transfer for unifi uplink - CONFIG |
| 863 |
if ( !$PluginConfig{'enable_xfer_device'} ) { return 0; }
|
| 864 |
|
| 865 |
print "multigraph unifi_xfer_by_uplink\n"; |
| 866 |
print "rx_speed.value " . $Data{'uplink'}{"rx_speed"} . "\n";
|
| 867 |
print "tx_speed.value " . $Data{'uplink'}{"tx_speed"} . "\n";
|
| 868 |
print "rx_bytes.value " . $Data{'uplink'}{"rx_bytes"} . "\n";
|
| 869 |
print "tx_bytes.value " . $Data{'uplink'}{"tx_bytes"} . "\n";
|
| 870 |
return 1; |
| 871 |
} |
| 872 |
|
| 873 |
sub do_values_xfer_by_device {
|
| 874 |
# Provide transfer for each unifi device - CONFIG |
| 875 |
if ( !$PluginConfig{'enable_xfer_device'} ) { return 0; }
|
| 876 |
|
| 877 |
print "multigraph unifi_xfer_per_device\n"; |
| 878 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 879 |
print $_ . "_rxbytes.value " . $Data{'device'}{$_}->{"rx"} , "\n";
|
| 880 |
print $_ . "_txbytes.value " . $Data{'device'}{$_}->{"tx"} , "\n";
|
| 881 |
} |
| 882 |
if ( $PluginConfig{'enable_detail_xfer_device'} ) {
|
| 883 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 884 |
print "multigraph unifi_xfer_per_device." , $_ , "\n"; |
| 885 |
print "rxbyte.value " , $Data{'device'}{$_}->{"rx"} , "\n";
|
| 886 |
print "txbyte.value " , $Data{'device'}{$_}->{"tx"} , "\n";
|
| 887 |
} |
| 888 |
} |
| 889 |
return 1; |
| 890 |
} |
| 891 |
|
| 892 |
sub do_values_cpu {
|
| 893 |
# Provide device CPU usage for each unifi device - VALUES |
| 894 |
if ( !$PluginConfig{'enable_device_cpu'} ) { return 0; }
|
| 895 |
|
| 896 |
print "multigraph unifi_device_cpu\n"; |
| 897 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 898 |
print $_ , ".value " , ( $Data{'device'}{$_}->{"cpu"} ) , "\n";
|
| 899 |
} |
| 900 |
return 1; |
| 901 |
} |
| 902 |
|
| 903 |
sub do_values_mem {
|
| 904 |
# Provide device memory usage for each unifi device - VALUES |
| 905 |
if ( !$PluginConfig{'enable_device_mem'} ) { return 0; }
|
| 906 |
|
| 907 |
print "multigraph unifi_device_mem\n"; |
| 908 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 909 |
print $_ , ".value " , ( $Data{'device'}{$_}->{"mem"} ) , "\n";
|
| 910 |
} |
| 911 |
return 1; |
| 912 |
} |
| 913 |
|
| 914 |
sub do_values_load {
|
| 915 |
# Provide device load average for each unifi device - VALUES |
| 916 |
if ( !$PluginConfig{'enable_device_load'} ) { return 0; }
|
| 917 |
|
| 918 |
print "multigraph unifi_device_load\n"; |
| 919 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 920 |
if ( $Data{'device'}{$_}->{'type'} eq 'ugw' ) { next; }
|
| 921 |
print $_ , ".value " , ( $Data{'device'}{$_}->{"load"} ) , "\n";
|
| 922 |
} |
| 923 |
return 1; |
| 924 |
} |
| 925 |
|
| 926 |
sub do_values_uptime {
|
| 927 |
# Provide device uptime for each unifi device - VALUES |
| 928 |
if ( !$PluginConfig{'enable_device_uptime'} ) { return 0; }
|
| 929 |
|
| 930 |
print "multigraph unifi_device_uptime\n"; |
| 931 |
foreach ( sort keys %{$Data{'device'}} ) {
|
| 932 |
print $_ , ".value " , ( $Data{'device'}{$_}->{"uptime"} / 86400 ) , "\n";
|
| 933 |
} |
| 934 |
return 1; |
| 935 |
} |
| 936 |
|
| 937 |
|
| 938 |
|
| 939 |
|
| 940 |
|
| 941 |
|
| 942 |
|
| 943 |
######################### |
| 944 |
# SUBROUTINES GENERAL # |
| 945 |
######################### |
| 946 |
|
| 947 |
sub graph_prologue {
|
| 948 |
# Generate graph prologues - slightly less copy-pasta, and less chance for things to go wrong |
| 949 |
my ( $id, $title, $args, $vlabel, $category, $info ) = (@_); |
| 950 |
|
| 951 |
print "multigraph $id\n"; |
| 952 |
print 'graph_title ' , $title , ' : ' , $APIconfig{"name"} , "\n";
|
| 953 |
print "graph_args $args\n"; |
| 954 |
print "graph_vlabel $vlabel\n"; |
| 955 |
if ( $PluginConfig{'force_category'} ) {
|
| 956 |
print "graph_category ", $PluginConfig{'force_category'}, "\n";
|
| 957 |
} else {
|
| 958 |
print "graph_category $category\n"; |
| 959 |
} |
| 960 |
if ( $info ) {
|
| 961 |
print 'graph_info For the unifi site named "' , $APIconfig{"name"} , "\", $info\n";
|
| 962 |
} |
| 963 |
return 1; |
| 964 |
} |
| 965 |
|
| 966 |
# Collate all collected data into something we can use. |
| 967 |
sub make_data {
|
| 968 |
foreach my $thisDevice ( @{$APIJsonResponse{'device'}->{'data'}} ) {
|
| 969 |
# Grab everything we care to know about each device. |
| 970 |
$Data{'device'}{ make_safe($thisDevice->{'name'}, $thisDevice->{'serial'}) } = {
|
| 971 |
'label' => $thisDevice->{'name'},
|
| 972 |
'users' => ($thisDevice->{'user-num_sta'} || 0),
|
| 973 |
'guests' => ($thisDevice->{'guest-num_sta'} || 0),
|
| 974 |
'clients' => ($thisDevice->{'user-num_sta'} + $thisDevice->{'guest-num_sta'} || 0),
|
| 975 |
'tx' => $thisDevice->{'rx_bytes'},
|
| 976 |
'rx' => $thisDevice->{'tx_bytes'},
|
| 977 |
'name' => $thisDevice->{'name'},
|
| 978 |
'uptime' => $thisDevice->{'uptime'},
|
| 979 |
'cpu' => $thisDevice->{'system-stats'}->{'cpu'},
|
| 980 |
'mem' => $thisDevice->{'system-stats'}->{'mem'},
|
| 981 |
'load' => ( $thisDevice->{'type'} eq 'ugw' ? 'U' : $thisDevice->{'sys_stats'}->{'loadavg_1'} ),
|
| 982 |
'type' => $thisDevice->{'type'}
|
| 983 |
}; |
| 984 |
|
| 985 |
if ( $thisDevice->{'type'} eq 'ugw' ) { # Handle firewall specially, record uplink and networks
|
| 986 |
foreach my $thisNet ( @{$thisDevice->{'network_table'}} ) {
|
| 987 |
$Data{'networks'}{ make_safe($thisNet->{'name'}, $thisNet->{'_id'} ) } = {
|
| 988 |
'label' => $thisNet->{'name'},
|
| 989 |
'tx' => $thisNet->{'tx_bytes'},
|
| 990 |
'rx' => $thisNet->{'rx_bytes'}
|
| 991 |
} |
| 992 |
} |
| 993 |
|
| 994 |
$Data{'uplink'}{'devName'} = $thisDevice->{'name'};
|
| 995 |
$Data{'uplink'}{'rx_speed'} = $thisDevice->{'speedtest-status'}->{'xput_download'} * 1000000;
|
| 996 |
$Data{'uplink'}{'tx_speed'} = $thisDevice->{'speedtest-status'}->{'xput_upload'} * 1000000;
|
| 997 |
|
| 998 |
foreach ( @{$thisDevice->{"port_table"}} ) {
|
| 999 |
if ( $_->{name} eq "wan" ) {
|
| 1000 |
$Data{'uplink'}{'rx_bytes'} = $_->{'rx_bytes'};
|
| 1001 |
$Data{'uplink'}{'tx_bytes'} = $_->{'tx_bytes'};
|
| 1002 |
} |
| 1003 |
} |
| 1004 |
} |
| 1005 |
|
| 1006 |
if ( $thisDevice->{'type'} eq 'usw' ) { # Handle swiches specially - record port stats
|
| 1007 |
my @port_list; |
| 1008 |
|
| 1009 |
foreach my $port ( @{$thisDevice->{'port_table'}} ) {
|
| 1010 |
if ( !$PluginConfig{'hide_empty_xfer_port'} || $port->{'up'} ) {
|
| 1011 |
push @port_list , {
|
| 1012 |
'name' => 'port_' . zPad($port->{'port_idx'}),
|
| 1013 |
'label' => zPad($port->{'port_idx'}) . '-' . $port->{'name'},
|
| 1014 |
'rx' => $port->{'rx_bytes'},
|
| 1015 |
'tx' => $port->{'tx_bytes'}
|
| 1016 |
}; |
| 1017 |
} |
| 1018 |
} |
| 1019 |
$Data{'device'}{ make_safe($thisDevice->{'name'}, $thisDevice->{'serial'}) }{'ports'} = \@port_list;
|
| 1020 |
} |
| 1021 |
|
| 1022 |
if ( $thisDevice->{'type'} eq 'uap' ) { # Handle APS specially - record radio stats
|
| 1023 |
my @theseRadios; |
| 1024 |
|
| 1025 |
foreach my $thisRadio ( @{$thisDevice->{'radio_table_stats'}} ) {
|
| 1026 |
my $name = make_safe( $thisRadio->{'name'}, "" );
|
| 1027 |
my $label = ( $thisRadio->{'channel'} < 12 ) ? '2.4Ghz' : '5Ghz';
|
| 1028 |
|
| 1029 |
$_ = $thisDevice->{'stat'}->{'ap'};
|
| 1030 |
|
| 1031 |
push @theseRadios, {
|
| 1032 |
'name' => $name, |
| 1033 |
'label' => $label . '-' . $thisDevice->{'name'},
|
| 1034 |
'pckt' => ($_->{$name . '-rx_packets'} // 0) + ($_->{$name . '-tx_packets'} // 0),
|
| 1035 |
'dret' => ($_->{$name . '-rx_dropped'} // 0) + ($_->{$name . '-tx_retries'} // 0) + ($_->{$name . '-tx_dropped'} // 0),
|
| 1036 |
'err' => ($_->{$name . '-rx_errors'} // 0) + ($_->{$name . '-tx_errors'} // 0),
|
| 1037 |
'type' => $label |
| 1038 |
}; |
| 1039 |
} |
| 1040 |
$Data{'device'}{ make_safe($thisDevice->{'name'}, $thisDevice->{'serial'}) }{'radio'} = \@theseRadios;
|
| 1041 |
} |
| 1042 |
} # END PROCESSING OF DEVICE DATA |
| 1043 |
|
| 1044 |
|
| 1045 |
# PROCESS NETWORK TYPE DATA |
| 1046 |
|
| 1047 |
# -> UNLESS, type graph is disabled. |
| 1048 |
# |
| 1049 |
# WHY: if the client list is large (huge. 10,000+), this is CPU intensive |
| 1050 |
if ( !$PluginConfig{'enable_clients_type'} ) { return 1; }
|
| 1051 |
|
| 1052 |
$Data{'types'} = {
|
| 1053 |
"wired" => ["Wired Connection", 1, 0, 0], |
| 1054 |
"wifi" => ["Wireless Connection", 1, 0, 0], |
| 1055 |
"tuser" => ["Total Users", 0, 0, 0], |
| 1056 |
"tguest" => ["Total Guests", 0, 0, 0], |
| 1057 |
"authed" => ["Authorized Guests", 0, 0, 0], |
| 1058 |
"unauth" => ["Unauthorized Guests", 0, 0, 0], |
| 1059 |
}; |
| 1060 |
|
| 1061 |
$Data{'typesOrder'} = ( $PluginConfig{'show_authorized_clients_type'} ) ?
|
| 1062 |
[ "wired", "wifi", "tuser", "tguest", "authed", "unauth"] : |
| 1063 |
[ "wired", "wifi", "tuser", "tguest" ]; |
| 1064 |
|
| 1065 |
|
| 1066 |
my @wlans; |
| 1067 |
|
| 1068 |
foreach my $thisNet ( @{$APIJsonResponse{'wlan'}->{'data'}} ) {
|
| 1069 |
$Data{'types'}{ make_safe($thisNet->{'name'}, "") } = [ $thisNet->{'name'}, 1, 0, 0 ];
|
| 1070 |
push @wlans, make_safe($thisNet->{'name'}, "");
|
| 1071 |
} |
| 1072 |
|
| 1073 |
foreach ( sort @wlans ) {
|
| 1074 |
push @{$Data{'typesOrder'}}, $_;
|
| 1075 |
} |
| 1076 |
|
| 1077 |
foreach my $client ( @{$APIJsonResponse{'sta'}->{'data'}} ) {
|
| 1078 |
if ( $client->{"is_wired"} ) {
|
| 1079 |
if ( $client->{"is_guest"} ) {
|
| 1080 |
$Data{'types'}->{'wired'}[3]++;
|
| 1081 |
$Data{'types'}->{'guest'}[3]++;
|
| 1082 |
} else {
|
| 1083 |
$Data{'types'}->{'wired'}[2]++;
|
| 1084 |
$Data{'types'}->{'user'}[2]++;
|
| 1085 |
} |
| 1086 |
} else {
|
| 1087 |
if ( $client->{"is_guest"} ) {
|
| 1088 |
$Data{'types'}->{make_safe($client->{"essid"}, "")}[3]++;
|
| 1089 |
$Data{'types'}->{'wifi'}[3]++;
|
| 1090 |
$Data{'types'}->{'guest'}[3]++;
|
| 1091 |
if ( $client->{"authorized"} ) {
|
| 1092 |
$Data{'types'}->{'authed'}[3]++;
|
| 1093 |
} else {
|
| 1094 |
$Data{'types'}->{'unauth'}[3]++;
|
| 1095 |
} |
| 1096 |
} else {
|
| 1097 |
$Data{'types'}->{make_safe($client->{"essid"}, "")}[2]++;
|
| 1098 |
$Data{'types'}->{'wifi'}[2]++;
|
| 1099 |
$Data{'types'}->{'user'}[2]++;
|
| 1100 |
} |
| 1101 |
} |
| 1102 |
} |
| 1103 |
|
| 1104 |
return 1; |
| 1105 |
} |
| 1106 |
|
| 1107 |
|
| 1108 |
sub fetch_data {
|
| 1109 |
# Set up curl, and login to API |
| 1110 |
$curl->setopt($curl->CURLOPT_POST,1); |
| 1111 |
$curl->setopt($curl->CURLOPT_COOKIEFILE,""); # Session only cookie |
| 1112 |
$curl->setopt($curl->CURLOPT_SSL_VERIFYPEER, (( $APIconfig{"ssl_verify_peer"} =~ m/no/i ) ? 0 : 1) );
|
| 1113 |
$curl->setopt($curl->CURLOPT_SSL_VERIFYHOST, (( $APIconfig{"ssl_verify_host"} =~ m/no/i ) ? 0 : 2) );
|
| 1114 |
$curl->setopt($curl->CURL_SSLVERSION_TLSv1, 1); |
| 1115 |
$curl->setopt($curl->CURLOPT_URL, $APIPoint{'login'});
|
| 1116 |
$curl->setopt($curl->CURLOPT_POSTFIELDS, q[{"username":"] . $APIconfig{"user"} . q[", "password":"] . $APIconfig{"pass"} . q["}] );
|
| 1117 |
$curl->setopt($curl->CURLOPT_WRITEDATA, \$APIResponse{'login'});
|
| 1118 |
$retcode = $curl->perform; |
| 1119 |
|
| 1120 |
if ( $retcode != 0 ) {
|
| 1121 |
die "FATAL:$me: Unable to connect to API: " . $curl->strerror($retcode) . " " . $curl->errbuf . "\n"; |
| 1122 |
} |
| 1123 |
|
| 1124 |
$APIJsonResponse{'login'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode($APIResponse{'login'});
|
| 1125 |
|
| 1126 |
if ( $APIJsonResponse{'login'}->{'meta'}->{'rc'} ne 'ok' ) {
|
| 1127 |
die "FATAL:$me: Unable to login to API - it said: " , $APIJsonResponse{'login'}->{'meta'}->{'msg'} , "\n";
|
| 1128 |
} |
| 1129 |
|
| 1130 |
# Change method to GET |
| 1131 |
$curl->setopt($curl->CURLOPT_HTTPGET,1); |
| 1132 |
|
| 1133 |
|
| 1134 |
# Get some API data. |
| 1135 |
|
| 1136 |
# Device data |
| 1137 |
$curl->setopt($curl->CURLOPT_WRITEDATA, \$APIResponse{'device'});
|
| 1138 |
$curl->setopt($curl->CURLOPT_URL, $APIPoint{'device'});
|
| 1139 |
$retcode = $curl->perform; |
| 1140 |
|
| 1141 |
if ( $retcode != 0 ) {
|
| 1142 |
die "FATAL:$me: Unable to connect to API: " . $curl->strerror($retcode) . " " . $curl->errbuf . "\n"; |
| 1143 |
} |
| 1144 |
|
| 1145 |
$APIJsonResponse{'device'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode($APIResponse{'device'});
|
| 1146 |
|
| 1147 |
if ( $APIJsonResponse{'device'}->{'meta'}->{'rc'} ne 'ok' ) {
|
| 1148 |
die "FATAL:$me: Unable get device data from API - it said: " , $APIJsonResponse{'device'}->{'meta'}->{'msg'} , "\n";
|
| 1149 |
} |
| 1150 |
|
| 1151 |
# STA (client) data |
| 1152 |
$curl->setopt($curl->CURLOPT_WRITEDATA, \$APIResponse{'sta'});
|
| 1153 |
$curl->setopt($curl->CURLOPT_URL, $APIPoint{'sta'});
|
| 1154 |
$retcode = $curl->perform; |
| 1155 |
|
| 1156 |
if ( $retcode != 0 ) {
|
| 1157 |
die "FATAL:$me: Unable to connect to API: " . $curl->strerror($retcode) . " " . $curl->errbuf . "\n"; |
| 1158 |
} |
| 1159 |
|
| 1160 |
$APIJsonResponse{'sta'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode($APIResponse{'sta'});
|
| 1161 |
|
| 1162 |
if ( $APIJsonResponse{'sta'}->{'meta'}->{'rc'} ne 'ok' ) {
|
| 1163 |
die "FATAL:$me: Unable get sta data from API - it said: " , $APIJsonResponse{'sta'}->{'meta'}->{'msg'} , "\n";
|
| 1164 |
} |
| 1165 |
|
| 1166 |
# WLAN data |
| 1167 |
$curl->setopt($curl->CURLOPT_WRITEDATA, \$APIResponse{'wlan'});
|
| 1168 |
$curl->setopt($curl->CURLOPT_URL, $APIPoint{'wlan'});
|
| 1169 |
$retcode = $curl->perform; |
| 1170 |
|
| 1171 |
if ( $retcode != 0 ) {
|
| 1172 |
die "FATAL:$me: Unable to connect to API: " . $curl->strerror($retcode) . " " . $curl->errbuf . "\n"; |
| 1173 |
} |
| 1174 |
|
| 1175 |
$APIJsonResponse{'wlan'} = $jsonOBJ->allow_nonref->utf8->relaxed->decode($APIResponse{'wlan'});
|
| 1176 |
|
| 1177 |
if ( $APIJsonResponse{'wlan'}->{'meta'}->{'rc'} ne 'ok' ) {
|
| 1178 |
die "FATAL:$me: Unable get wlan data from API - it said: " , $APIJsonResponse{'wlan'}->{'meta'}->{'msg'} , "\n";
|
| 1179 |
} |
| 1180 |
} |
| 1181 |
|
| 1182 |
# Make field names safe, and lowercase. |
| 1183 |
# |
| 1184 |
# Typically, $extraName should be the MAC address of the unique ID identifier as the unifi |
| 1185 |
# controller software does not enforce that device names or network names are unique. |
| 1186 |
sub make_safe {
|
| 1187 |
my ( $name, $extraName ) = ( @_ ); |
| 1188 |
if ( $extraName ne "" ) {
|
| 1189 |
return clean_fieldname(lc($name) . "_" . $extraName); |
| 1190 |
} else {
|
| 1191 |
return lc(clean_fieldname($name)); |
| 1192 |
} |
| 1193 |
} |
| 1194 |
|
| 1195 |
# Get a default from an environmental variable - return text |
| 1196 |
# |
| 1197 |
# env_default(<variable name>, <default>) |
| 1198 |
sub env_default_text {
|
| 1199 |
my ( $env_var, $default ) = (@_); |
| 1200 |
return ( ( defined $ENV{$env_var} ) ? $ENV{$env_var} : $default ),
|
| 1201 |
} |
| 1202 |
|
| 1203 |
# Get a default from an environmental variable - boolean true |
| 1204 |
# |
| 1205 |
# env_default_bool_true (<variable name>, <default>) |
| 1206 |
sub env_default_bool_true {
|
| 1207 |
my $env_var = $_[0]; |
| 1208 |
return ( ( defined $ENV{$env_var} && $ENV{$env_var} =~ m/no/i ) ? 0 : 1 );
|
| 1209 |
} |
| 1210 |
|
| 1211 |
# Quick 2 digit zero pad |
| 1212 |
sub zPad { return sprintf("%02d", $_[0]); }
|
