parent
b41cc0b2d6
commit
30b6fdad55
3 changed files with 269 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||||
|
UserParameter=unifi.discovery[*],/var/lib/zabbix/bin/disco_unifi --url=$1 --user=$2 --pass=$3 --site=$4 --what=$5 --type=$6 |
||||||
|
UserParameter=unifi.check.all[*],/var/lib/zabbix/bin/check_unifi --url=$1 --user=$2 --pass=$3 --site=$4 --$5 $6 |
@ -0,0 +1,155 @@ |
|||||||
|
#!/usr/bin/perl -w |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use JSON; |
||||||
|
use Getopt::Long; |
||||||
|
use LWP::UserAgent; |
||||||
|
use Data::Dumper; |
||||||
|
|
||||||
|
my $user = 'zabbix'; |
||||||
|
my $pass = 'secret'; |
||||||
|
my $site = 'default'; |
||||||
|
my $url = 'https://localhost:8443'; |
||||||
|
my $unifi; |
||||||
|
my $dev; |
||||||
|
my $client; |
||||||
|
my $net; |
||||||
|
my $wlan; |
||||||
|
my $pretty = 0; |
||||||
|
|
||||||
|
my $json = {}; |
||||||
|
my $site_id; |
||||||
|
|
||||||
|
GetOptions ( |
||||||
|
'user=s' => \$user, |
||||||
|
'password|p=s' => \$pass, |
||||||
|
'site=s' => \$site, |
||||||
|
'url=s' => \$url, |
||||||
|
'unifi' => \$unifi, |
||||||
|
'dev=s' => \$dev, |
||||||
|
'client=s' => \$client, |
||||||
|
'net=s' => \$net, |
||||||
|
'wlan=s' => \$wlan, |
||||||
|
'pretty' => \$pretty |
||||||
|
); |
||||||
|
|
||||||
|
# Log into the API |
||||||
|
my $resp; |
||||||
|
my $ua = LWP::UserAgent->new( |
||||||
|
ssl_opts => { verify_hostname => 0 }, |
||||||
|
cookie_jar => {} |
||||||
|
); |
||||||
|
$resp = $ua->post( |
||||||
|
$url . '/api/login', |
||||||
|
Content => to_json({ username => $user, password => $pass }), |
||||||
|
Content_Type => 'application/json;charset=UTF-8' |
||||||
|
); |
||||||
|
die "Login failed: " . $resp->message . "\n" if $resp->is_error; |
||||||
|
|
||||||
|
# Now, we need to get the site ID |
||||||
|
$resp = $ua->get($url . '/api/self/sites'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
if ($_->{name} eq $site || $_->{desc} eq $site){ |
||||||
|
$site_id = $_->{_id}; |
||||||
|
# If site is referenced by description, translate it to name |
||||||
|
$site = $_->{name} if ($_->{name} ne $site); |
||||||
|
last; |
||||||
|
} |
||||||
|
} |
||||||
|
die "Site $site not found\n" unless ($site_id); |
||||||
|
|
||||||
|
# Global info about the instance of Unifi |
||||||
|
if ($unifi){ |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/health'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
if ($entry->{subsystem} eq 'wlan'){ |
||||||
|
$json->{wireless_clients} = $entry->{num_user}; |
||||||
|
$json->{wireless_guests} = $entry->{num_guest}; |
||||||
|
} elsif ($entry->{subsystem} eq 'lan'){ |
||||||
|
$json->{wired_clients} = $entry->{num_user}; |
||||||
|
$json->{wired_guests} = $entry->{num_guest}; |
||||||
|
} |
||||||
|
foreach (qw/adopted pending disabled/){ |
||||||
|
$json->{'dev_' . $_} += $entry->{'num_' . $_} if ($entry->{'num_' . $_}); |
||||||
|
} |
||||||
|
foreach (qw/num_ap num_sw num_gw/){ |
||||||
|
$json->{$_} += $entry->{$_} if ($entry->{$_}); |
||||||
|
} |
||||||
|
} |
||||||
|
$json->{$_} ||= 0 foreach (qw/wireless_clients wireless_guests |
||||||
|
wired_clients wired_guests dev_adopted |
||||||
|
dev_pending dev_disabled num_ap num_sw |
||||||
|
num_gw/); |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/sysinfo'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
$json->{$_} = from_json($resp->decoded_content)->{data}->[0]->{$_} |
||||||
|
foreach (qw/version build update_available/); |
||||||
|
|
||||||
|
} elsif ($dev) { |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/device/' . $dev); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
my $obj = from_json($resp->decoded_content)->{data}->[0]; |
||||||
|
foreach (qw/sys_stats locating serial name num_sta user-num_sta |
||||||
|
guest-num_sta inform_url version model state type |
||||||
|
cfgversion adopted avg_client_signal/){ |
||||||
|
$json->{$_} = $obj->{$_} if ($obj->{$_}); |
||||||
|
} |
||||||
|
foreach (qw/guest-rx_packets guest-tx_packets guest-rx_bytes |
||||||
|
guest-tx_bytes user-rx_packets user-tx_packets |
||||||
|
user-rx_bytes user-tx_bytes rx_packets tx_packets |
||||||
|
rx_bytes tx_bytes rx_errors tx_errors |
||||||
|
rx_dropped tx_dropped/){ |
||||||
|
$json->{net_stats}->{$_} = $obj->{stat}->{$_} if ($obj->{stat}->{$_}); |
||||||
|
} |
||||||
|
# Convert last seen into a relative time |
||||||
|
$json->{last_seen} = time - $obj->{last_seen}; |
||||||
|
# Add some more info in sys_stats |
||||||
|
$json->{sys_stats}->{$_} = $obj->{'system-stats'}->{$_} foreach (qw/cpu mem uptime/); |
||||||
|
# Count the number of SSID served |
||||||
|
$json->{num_wlan} = scalar @{$obj->{radio_table}} if ($obj->{radio_table}); |
||||||
|
} elsif ($client) { |
||||||
|
|
||||||
|
} elsif ($wlan) { |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/rest/wlanconf/' . $wlan); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
my $obj = from_json($resp->decoded_content)->{data}->[0]; |
||||||
|
foreach (qw/name enabled is_guest mac_filter_enabled security |
||||||
|
mac_filter_policy vlan vlan_enabled/){ |
||||||
|
$json->{$_} = $obj->{$_}; |
||||||
|
} |
||||||
|
|
||||||
|
# Now, we need to count stations for each SSID |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/sta'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
$json->{$_} = 0 foreach (qw/avg_rx_rate_ac avg_tx_rate_ac avg_rx_rate_ng |
||||||
|
avg_tx_rate_ng num_sta num_sta_ac num_sta_ng/); |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
next if (not $entry->{essid} or $entry->{essid} ne $json->{name} or $entry->{is_wired} == JSON::PP::true); |
||||||
|
$json->{num_sta}++; |
||||||
|
if ($entry->{radio_proto} eq 'ac'){ |
||||||
|
$json->{num_sta_ac}++; |
||||||
|
$json->{avg_rx_rate_ac} += $entry->{rx_rate}; |
||||||
|
$json->{avg_tx_rate_ac} += $entry->{tx_rate}; |
||||||
|
} elsif ($entry->{radio_proto} eq 'ng'){ |
||||||
|
$json->{num_sta_ng}++; |
||||||
|
$json->{avg_rx_rate_ng} += $entry->{rx_rate}; |
||||||
|
$json->{avg_tx_rate_ng} += $entry->{tx_rate}; |
||||||
|
} |
||||||
|
$json->{$_} += $entry->{$_} foreach (qw/rx_bytes tx_bytes rx_packets tx_packets/); |
||||||
|
$json->{'avg_' . $_} += $entry->{$_} foreach (qw/satisfaction tx_power signal noise/); |
||||||
|
} |
||||||
|
# Now lets compute average values |
||||||
|
$json->{'avg_' . $_} = ($json->{num_sta} == 0) ? 0 : $json->{'avg_' . $_} / $json->{num_sta} |
||||||
|
foreach (qw/satisfaction tx_power signal noise/); |
||||||
|
$json->{$_} = ($json->{num_sta_ac} == 0) ? 0 : $json->{$_} / $json->{num_sta_ac} |
||||||
|
foreach (qw/avg_rx_rate_ac avg_tx_rate_ac/); |
||||||
|
$json->{$_} = ($json->{num_sta_ng} == 0) ? 0 : $json->{$_} / $json->{num_sta_ng} |
||||||
|
foreach (qw/avg_rx_rate_ng avg_tx_rate_ng/); |
||||||
|
} |
||||||
|
|
||||||
|
# TODO: convert JSON bool to 0/1 |
||||||
|
|
||||||
|
print to_json($json, { pretty => $pretty }); |
@ -0,0 +1,112 @@ |
|||||||
|
#!/usr/bin/perl -w |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use JSON; |
||||||
|
use Getopt::Long; |
||||||
|
use LWP::UserAgent; |
||||||
|
use Data::Dumper; |
||||||
|
|
||||||
|
my $user = 'zabbix'; |
||||||
|
my $pass = 'secret'; |
||||||
|
my $site = 'default'; |
||||||
|
my $url = 'https://localhost:8443'; |
||||||
|
my $what = 'devices'; |
||||||
|
my $type = 'all'; |
||||||
|
my $pretty = 0; |
||||||
|
|
||||||
|
my $json = {}; |
||||||
|
@{$json->{data}} = (); |
||||||
|
|
||||||
|
GetOptions ( |
||||||
|
'user=s' => \$user, |
||||||
|
'password|p=s' => \$pass, |
||||||
|
'site=s' => \$site, |
||||||
|
'url=s' => \$url, |
||||||
|
'what=s' => \$what, |
||||||
|
'type:s' => \$type, |
||||||
|
'pretty' => \$pretty |
||||||
|
); |
||||||
|
|
||||||
|
# An empty type is the same as all |
||||||
|
$type = 'all' if ($type eq ''); |
||||||
|
my $site_id; |
||||||
|
my $resp; |
||||||
|
my $ua = LWP::UserAgent->new( |
||||||
|
ssl_opts => { verify_hostname => 0 }, |
||||||
|
cookie_jar => {} |
||||||
|
); |
||||||
|
|
||||||
|
# Login on the API |
||||||
|
$resp = $ua->post( |
||||||
|
$url . '/api/login', |
||||||
|
Content => to_json({ username => $user, password => $pass }), |
||||||
|
Content_Type => 'application/json;charset=UTF-8' |
||||||
|
); |
||||||
|
die "Login failed: " . $resp->message . "\n" if $resp->is_error; |
||||||
|
# Now, we need to get the site ID |
||||||
|
$resp = $ua->get($url . '/api/self/sites'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
if ($_->{name} eq $site || $_->{desc} eq $site){ |
||||||
|
$site_id = $_->{_id}; |
||||||
|
# If site is referenced by description, translate it to name |
||||||
|
$site = $_->{name} if ($_->{name} ne $site); |
||||||
|
last; |
||||||
|
} |
||||||
|
} |
||||||
|
die "Site $site not found\n" unless ($site_id); |
||||||
|
|
||||||
|
if ($what eq 'devices'){ |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/device'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
next if ($type ne 'all' && $entry->{type} ne $type); |
||||||
|
push @{$json->{data}}, { |
||||||
|
'{#UNIFI_DEV_ID}' => $entry->{device_id}, |
||||||
|
'{#UNIFI_DEV_ADOPTED}' => $entry->{adopted}, |
||||||
|
'{#UNIFI_DEV_MODEL}' => $entry->{model}, |
||||||
|
'{#UNIFI_DEV_NAME}' => $entry->{name}, |
||||||
|
'{#UNIFI_DEV_MAC}' => $entry->{mac}, |
||||||
|
'{#UNIFI_DEV_TYPE}' => $entry->{type} |
||||||
|
}; |
||||||
|
} |
||||||
|
} elsif ($what eq 'clients'){ |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/stat/alluser'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
# Ignore other sites |
||||||
|
next if ($entry->{site_id} ne $site_id); |
||||||
|
# Ignore clients not seen since more than 30 days |
||||||
|
next if (time - $entry->{last_seen} > 2592000); |
||||||
|
next if ($type eq 'wireless' and $entry->{is_wired} eq 'true'); |
||||||
|
next if ($type eq 'wired' and $entry->{is_wired} eq 'false'); |
||||||
|
push @{$json->{data}}, { |
||||||
|
'{#UNIFI_STA_ID}' => $entry->{_id}, |
||||||
|
'{#UNIFI_STA_NAME}' => (defined $entry->{hostname}) ? $entry->{hostname} : $entry->{mac} |
||||||
|
}; |
||||||
|
} |
||||||
|
} elsif ($what eq 'networks'){ |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/rest/networkconf'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
# Ignore other sites |
||||||
|
next if ($entry->{site_id} ne $site_id); |
||||||
|
next if ($type ne 'all' and $entry->{purpose} ne $type); |
||||||
|
push @{$json->{data}}, { |
||||||
|
'{#UNIFI_NET_ID}' => $entry->{_id}, |
||||||
|
'{#UNIFI_NET_NAME}' => $entry->{name} |
||||||
|
}; |
||||||
|
} |
||||||
|
} elsif ($what eq 'wlan') { |
||||||
|
$resp = $ua->get($url . '/api/s/' . $site . '/rest/wlanconf'); |
||||||
|
die $resp->message . "\n" if $resp->is_error; |
||||||
|
foreach my $entry (@{from_json($resp->decoded_content)->{data}}){ |
||||||
|
push @{$json->{data}}, { |
||||||
|
'{#UNIFI_WLAN_ID}' => $entry->{_id}, |
||||||
|
'{#UNIFI_WLAN_NAME}' => $entry->{name} |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
print to_json($json, { pretty => $pretty }); |
Loading…
Reference in new issue