ソースを参照

add config options for cacti|torrus|nagios|wiki|stat url
add nagios directory for OU
upload foswiki plugins for stat, ups, capsman miktorik, huwawei WLC
add scripts for sync wiki fields in stat

Dmitriev Roman 5 年 前
コミット
3068694b01

+ 20 - 18
docs/mysql/stat_table_OU.sql

@@ -7,27 +7,29 @@
 
 
 CREATE TABLE `OU` (
 CREATE TABLE `OU` (
   `id` int(11) NOT NULL,
   `id` int(11) NOT NULL,
-  `ou_name` varchar(40) DEFAULT NULL
+  `ou_name` varchar(40) DEFAULT NULL,
+  `nagios_dir` varchar(255) DEFAULT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
 --
 --
 -- Дамп данных таблицы `OU`
 -- Дамп данных таблицы `OU`
 --
 --
 
 
-INSERT INTO `OU` (`id`, `ou_name`) VALUES
-(0, 'Все'),
-(1, 'Сервера'),
-(2, 'Администраторы'),
-(3, 'Пользователи'),
-(4, 'VOIP'),
-(5, 'IPCAM'),
-(6, 'Принтеры'),
-(7, 'Свичи'),
-(8, 'UPS'),
-(9, 'Охрана'),
-(10, 'Роутеры'),
-(11, 'IPTV'),
-(12, 'WiFi AP'),
-(13, 'Техподдержка'),
-(14, 'POS-терминалы'),
-(23, 'WiFi');
+INSERT INTO `OU` (`id`, `ou_name`, `nagios_dir`) VALUES
+(0, 'Все', '/etc/nagios/any'),
+(1, 'Сервера', NULL),
+(2, 'Администраторы', NULL),
+(3, 'Пользователи', NULL),
+(4, 'VOIP', '/etc/nagios/voip'),
+(5, 'IPCAM', '/etc/nagios/videocam'),
+(6, 'Принтеры', '/etc/nagios/printers'),
+(7, 'Свичи', '/etc/nagios/switches'),
+(8, 'UPS', '/etc/nagios/ups'),
+(9, 'Охрана', '/etc/nagios/security'),
+(10, 'Роутеры', '/etc/nagios/routers'),
+(11, 'IPTV', NULL),
+(12, 'WiFi AP', '/etc/nagios/ap'),
+(13, 'Техподдержка', NULL),
+(14, 'POS-терминалы', NULL),
+(23, 'WiFi', NULL),
+(24, 'VPN', NULL);

+ 8 - 1
docs/mysql/stat_table_config_options.sql

@@ -58,4 +58,11 @@ INSERT INTO `config_options` (`id`, `option_name`, `description`, `uniq`, `type`
 (52, 'Sender email', 'E-mail адрес, с которого рассылается почта', 1, 'text', 'root', 0, 0),
 (52, 'Sender email', 'E-mail адрес, с которого рассылается почта', 1, 'text', 'root', 0, 0),
 (53, 'log level', 'Каждый уровень включает в себя предыдущий:\r\n0 - ERROR - писать только ошибки\r\n1 - WARNING - писать предупреждения\r\n2 - INFO - писать информационные сообщения\r\n3 - VERBOSE - писать подробную информацию о выполняемых операциях', 1, 'int', '2', 0, 3),
 (53, 'log level', 'Каждый уровень включает в себя предыдущий:\r\n0 - ERROR - писать только ошибки\r\n1 - WARNING - писать предупреждения\r\n2 - INFO - писать информационные сообщения\r\n3 - VERBOSE - писать подробную информацию о выполняемых операциях', 1, 'int', '2', 0, 3),
 (54, 'enable_quotes', 'Включить обработку квот по трафику', 1, 'bool', '0', 0, 0),
 (54, 'enable_quotes', 'Включить обработку квот по трафику', 1, 'bool', '0', 0, 0),
-(55, 'netflow_step', 'Интервал сброса данных из коллектора netflow, минуты', 1, 'int', '10', 1, 60);
+(55, 'netflow_step', 'Интервал сброса данных из коллектора netflow, минуты', 1, 'int', '10', 1, 60),
+(56, 'traffic_ipstat_history', 'Время хранения полной статистики по трафику для каждого ip-адреса в сутках. Таблица в 6 раз больше обычной часовой статистики. Врядли кому-то потребуется глубина хранения более месяца.', 1, 'int', '30', 7, 365),
+(57, 'nagios_url', 'Адрес сайта nagios', 1, 'text', 'http://127.0.0.1/nagios', 0, 0),
+(58, 'cacti_url', 'Адрес сайта cacti', 1, 'text', 'http://127.0.0.1/cacti', 0, 0),
+(59, 'torrus_url', 'Адрес сайта Torrus', 1, 'text', 'http://127.0.0.1/torrus', 0, 0),
+(60, 'wiki_url', 'Адрес wiki', 1, 'text', 'http://127.0.0.1/wiki', 0, 0),
+(61, 'wiki_path', 'Путь к каталогу данных вики', 1, 'text', '/var/www/foswiki/data/', 0, 0),
+(62, 'stat_url', 'Адрес этого сайта', 1, 'text', 'http://127.0.0.1/stat', 0, 0);

+ 354 - 0
docs/wiki/foswiki/CapsManPlugin.pm

@@ -0,0 +1,354 @@
+package Foswiki::Plugins::CapsManPlugin;
+
+use utf8;
+use Net::SNMP qw(:snmp ticks_to_time TRANSLATE_NONE);
+use Net::Ping;
+
+# Always use strict to enforce variable scoping
+use strict;
+
+# $VERSION is referred to by Foswiki, and is the only global variable that
+# *must* exist in this package
+use vars qw( $VERSION $RELEASE $debug $pluginName );
+
+use Foswiki::Func    ();    # The plugins API
+use Foswiki::Plugins ();    # For the API version
+
+# This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
+# status of the plugin. It is used by the build automation tools, so
+# you should leave it alone.
+$VERSION = '$Rev: 8713$';
+
+# This is a free-form string you can use to "name" your own plugin version.
+# It is *not* used by the build automation tools, but is reported as part
+# of the version number in PLUGINDESCRIPTIONS.
+$RELEASE = '1.01';
+
+# Name of this Plugin, only used in this module
+$pluginName = 'CapsManPlugin';
+
+=pod
+
+---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
+   * =$topic= - the name of the topic in the current CGI query
+   * =$web= - the name of the web in the current CGI query
+   * =$user= - the login name of the user
+   * =$installWeb= - the name of the web the plugin is installed in
+
+REQUIRED
+
+Called to initialise the plugin. If everything is OK, should return
+a non-zero value. On non-fatal failure, should write a message
+using Foswiki::Func::writeWarning and return 0. In this case
+%FAILEDPLUGINS% will indicate which plugins failed.
+
+In the case of a catastrophic failure that will prevent the whole
+installation from working safely, this handler may use 'die', which
+will be trapped and reported in the browser.
+
+You may also call =Foswiki::Func::registerTagHandler= here to register
+a function to handle tags that have standard Foswiki syntax - for example,
+=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
+Foswiki tag handling functions this way, though this practice is unsupported
+and highly dangerous!
+
+=cut
+
+sub initPlugin {
+    my( $topic, $web, $user, $installWeb ) = @_;
+
+    # check for Plugins.pm versions
+    if( $Foswiki::Plugins::VERSION < 1.026 ) {
+        Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
+        return 0;
+    }
+
+    Foswiki::Func::registerTagHandler( 'CapsManINFO', \&_CapsManINFO );
+
+    # Plugin correctly initialized
+    return 1;
+}
+
+sub table_callback {
+my ($session, $OID_ifTable, $table) = @_;
+
+my $list = $session->var_bind_list();
+if (!defined $list) {
+    printf "ERROR: %s\n", $session->error();
+    return;
+    }
+
+my @names = $session->var_bind_names();
+my $next  = undef;
+
+while (@names) {
+   $next = shift @names;
+   if (!oid_base_match($OID_ifTable, $next)) {
+      return; # Table is done.
+      }
+   $table->{$next} = $list->{$next};
+}
+
+my $result = $session->get_bulk_request( -varbindlist => [ $next ], -maxrepetitions => 10, );
+if (!defined $result) { printf "ERROR: %s.\n", $session->error(); }
+return;
+}
+
+sub StrToIp{
+return unpack('N',pack('C4',split(/\./,$_[0])));
+}
+
+sub get_last_dec {
+my $oid = shift;
+if ($oid=~/\.(\d*)$/) { return $1; }
+return '';
+}
+
+sub get_first_dec {
+my $oid = shift;
+if ($oid=~/(.*)\.(\d*)$/) { return $1; }
+return $oid;
+}
+
+sub extract_dec_mac {
+my $base_oid = shift;
+my $key = shift;
+$key =~s/^$base_oid\.//;
+return $key;
+}
+
+sub mac_splitted{
+my $mac=shift;
+return if (!$mac);
+my $ch=shift || ":";
+$mac=~s/(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})/$1:$2:$3:$4:$5:$6/g;
+if ($ch ne ":") { $mac=~s/\:/$ch/g; }
+return $mac;
+}
+
+sub dec2mac {
+my $key = shift;
+my @dec_mac = split(/\./,$key);
+my @mac=();
+for (my $i = 0; $i < scalar(@dec_mac); $i++) { $mac[$i]=sprintf("%02x",$dec_mac[$i]); }
+$key = join(':',@mac);
+return $key;
+}
+
+sub expand_status {
+my $client = shift;
+my $ret ='';
+foreach my $id (sort keys %$client) {
+        $ret.='| '.$client->{$id}->{int_name}.' | ';
+        $ret.=$client->{$id}->{SSID}.' | ';
+        $ret.=$client->{$id}->{mac}.' | ';
+        $ret.=$client->{$id}->{rx}.' dBm / '.$client->{$id}->{tx}.'dBm | ';
+        $ret.=$client->{$id}->{rxrate}.'M / '.$client->{$id}->{txrate}.'M | ';
+        $ret.=$client->{$id}->{uptime}." |\n";
+        }
+return $ret;
+};
+
+sub _CapsManINFO {
+my($session, $params, $theTopic, $theWeb) = @_;
+
+my $host = $params->{_DEFAULT} || $params->{host};
+
+### check host alive
+my $p = Net::Ping->new("tcp",1,1);
+my $ok= $p->ping($host);
+$p->close();
+if (!$ok) {  return "Ups $host is not available<BR>"; }
+
+undef($p);
+
+my $port = $params->{port} || 161;
+my $timeout = $params->{timeout} || 5;
+
+my $community = $params->{community};
+$community =  'public' if (!$community);
+
+#1 - client list
+#2 - mac list
+#3 - ssid list
+
+my $mode = $params->{mode} || '3';
+
+my $snmp_session;
+my $error;
+
+my %DefaultMibs=(
+'Description'    => '.1.3.6.1.2.1.1.1.0',
+'Uptime'         => '.1.3.6.1.2.1.1.3.0',
+'Name'           => '.1.3.6.1.2.1.1.5.0',
+);
+
+my %MikrotikCapsManMibs=(
+'ClientMac'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.1',
+'ClientUptime'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.3',
+'ClientTxRate'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.8',
+'ClientRxRate'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.9',
+'ClientTx'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.10',
+'ClientRx'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.11',
+'ClientSSID'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.12',
+'InterfaceList'=>'.1.3.6.1.4.1.14988.1.1.14.1.1.2',
+#'APNames'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.2',
+#'APStatus'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.3',
+#'APAddress'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.4',
+#'APRadioCount'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.5',
+);
+
+### open SNMP session
+eval {
+    ($snmp_session, $error) = Net::SNMP->session(
+    -hostname  => $host,
+    -community => $community,
+    -nonblocking => 1,
+    -translate   => [-octetstring => 0],
+    -version     => 'snmpv2c',
+    );
+};
+
+return "CapsMan is not available<BR>"  if (!defined($snmp_session));
+
+$snmp_session->translate([-timeticks]);
+
+my %defaultTable;
+my $ret = $snmp_session->get_bulk_request(
+    -varbindlist    => [ '.1.3.6.1.2.1.1' ],
+    -callback       => [ \&table_callback, '.1.3.6.1.2.1.1', \%defaultTable ],
+    -maxrepetitions => 10,
+    );
+
+if (!defined $ret) {
+    $snmp_session->close();
+    return "CapsMan not answer!<BR>";
+    }
+# Now initiate the SNMP message exchange.
+snmp_dispatcher();
+
+my %CapsManTable;
+
+foreach my $key (keys %MikrotikCapsManMibs) {
+my $Mikrotik_CapsMan_mib = $MikrotikCapsManMibs{$key};
+my %table;
+my $result = $snmp_session->get_bulk_request(
+    -varbindlist    => [ $Mikrotik_CapsMan_mib ],
+    -callback       => [ \&table_callback, $Mikrotik_CapsMan_mib, \%table ],
+    -maxrepetitions => 10,
+    );
+if (!defined $result) {
+    printf "ERROR: %s\n", $snmp_session->error();
+    $snmp_session->close();
+    exit 1;
+    }
+# Now initiate the SNMP message exchange.
+snmp_dispatcher();
+$CapsManTable{$key}=\%table;
+}
+
+$snmp_session->close();
+
+my %interfaces;
+foreach my $interface_oid (keys %{$CapsManTable{InterfaceList}}) {
+$interfaces{extract_dec_mac($MikrotikCapsManMibs{InterfaceList},$interface_oid)}=$CapsManTable{InterfaceList}->{$interface_oid};
+}
+
+my $result=$defaultTable{$DefaultMibs{Name}}."\n<br>";
+$result.=$defaultTable{$DefaultMibs{Description}}."\n<br>";
+my $uptime = int($defaultTable{$DefaultMibs{Uptime}}/100);
+my $day; my $hour; my $min;
+$day = int($uptime/86400);
+$hour = int(($uptime - 86400*$day)/3600);
+$min = int (($uptime - 86400*$day - 3600*$hour)/60);
+my $s_uptime = "$day days $hour:$min";
+$result.= "$s_uptime\n<br>\n";
+
+my %client_status;
+
+my $key = 'ClientMac';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $int_id = get_last_dec($dec_oid);
+$client_status{$dec_mac}->{mac}=dec2mac($dec_mac);
+$client_status{$dec_mac}->{int_id}=$int_id;
+$client_status{$dec_mac}->{int_name}=$interfaces{$int_id};
+}
+
+$key = 'ClientTxRate';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $rate = $CapsManTable{$key}->{$oid};
+$client_status{$dec_mac}->{txrate}=$rate/1000000;
+}
+
+$key = 'ClientRxRate';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $rate = $CapsManTable{$key}->{$oid};
+$client_status{$dec_mac}->{rxrate}=$rate/1000000;
+}
+
+$key = 'ClientTx';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $rate = $CapsManTable{$key}->{$oid};
+$client_status{$dec_mac}->{tx}=$rate;
+}
+
+$key = 'ClientRx';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $rate = $CapsManTable{$key}->{$oid};
+$client_status{$dec_mac}->{rx}=$rate;
+}
+
+$key = 'ClientSSID';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $ssid = $CapsManTable{$key}->{$oid};
+$client_status{$dec_mac}->{SSID}=$ssid;
+}
+
+$key = 'ClientUptime';
+for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
+my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
+my $dec_mac = get_first_dec($dec_oid);
+my $uptime = $CapsManTable{$key}->{$oid};
+my $day; my $hour; my $min;
+$day = int($uptime/86400);
+$hour = int(($uptime - 86400*$day)/3600);
+$min = int (($uptime - 86400*$day - 3600*$hour)/60);
+my $s_uptime = "$day days $hour:$min";
+$client_status{$dec_mac}->{uptime}=$s_uptime;
+}
+
+my %CapsMan_status;
+my $all_clients=0;
+foreach my $dec_mac (sort keys %client_status) {
+my $ssid = $client_status{$dec_mac}->{SSID};
+if (!exists($CapsMan_status{$ssid})) { $CapsMan_status{$ssid}{count}=0; }
+$CapsMan_status{$ssid}{count}++;
+$all_clients++;
+}
+
+$result.="\n<br>Wireless counters:\n<br>\n";
+$result.="| *SSID* | *Count* |\n";
+foreach my $ssid (sort keys %CapsMan_status) {
+$result.= "| $ssid | $CapsMan_status{$ssid}{count} |\n";
+}
+$result.= "\n<br>Total: $all_clients\n<br>\n";
+$result.= "| *Interface* | *SSID* | *Client* | *Rx/Tx* | *Bitr* | *Uptime* |\n";
+
+$result.=expand_status(\%client_status);
+
+return $result;
+}
+
+1;

+ 148 - 0
docs/wiki/foswiki/ShowStatPlugin.pm

@@ -0,0 +1,148 @@
+package Foswiki::Plugins::ShowStatPlugin;
+
+# Always use strict to enforce variable scoping
+use strict;
+
+use utf8;
+use DBI;
+use Data::Dumper;
+
+# $VERSION is referred to by Foswiki, and is the only global variable that
+# *must* exist in this package
+use vars qw( $VERSION $RELEASE $debug $dbstat $dbcacti $pluginName );
+
+use Foswiki::Func    ();    # The plugins API
+use Foswiki::Plugins ();    # For the API version
+
+# This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
+# status of the plugin. It is used by the build automation tools, so
+# you should leave it alone.
+$VERSION = '$Rev: 8713$';
+
+# This is a free-form string you can use to "name" your own plugin version.
+# It is *not* used by the build automation tools, but is reported as part
+# of the version number in PLUGINDESCRIPTIONS.
+$RELEASE = '1.01';
+
+# Name of this Plugin, only used in this module
+$pluginName = 'ShowStatPlugin';
+
+=pod
+
+---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
+   * =$topic= - the name of the topic in the current CGI query
+   * =$web= - the name of the web in the current CGI query
+   * =$user= - the login name of the user
+   * =$installWeb= - the name of the web the plugin is installed in
+
+REQUIRED
+
+Called to initialise the plugin. If everything is OK, should return
+a non-zero value. On non-fatal failure, should write a message
+using Foswiki::Func::writeWarning and return 0. In this case
+%FAILEDPLUGINS% will indicate which plugins failed.
+
+In the case of a catastrophic failure that will prevent the whole
+installation from working safely, this handler may use 'die', which
+will be trapped and reported in the browser.
+
+You may also call =Foswiki::Func::registerTagHandler= here to register
+a function to handle tags that have standard Foswiki syntax - for example,
+=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
+Foswiki tag handling functions this way, though this practice is unsupported
+and highly dangerous!
+
+=cut
+
+sub initPlugin {
+    my( $topic, $web ) = @_;
+
+    # check for Plugins.pm versions
+    if( $Foswiki::Plugins::VERSION < 1.026 ) {
+        Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
+        return 0;
+        }
+
+    return 0 unless $Foswiki::cfg{Plugins}{DatabasePlugin}{ConfigSource};
+    if ( $Foswiki::cfg{Plugins}{DatabasePlugin}{ConfigSource} eq 'Local' ) {
+        foreach  my $info ( @{ $Foswiki::cfg{Plugins}{DatabasePlugin}{Databases} } ) {
+            if ($info->{description} eq "stat") { $dbstat = $info; next; }
+            if ($info->{description} eq "cacti") { $dbcacti = $info; next; }
+            }
+      }
+
+    return 0 if (!$dbstat);
+
+    # register the _EXAMPLETAG function to handle %EXAMPLETAG{...}%
+    Foswiki::Func::registerTagHandler( 'SHOWSTAT', \&_ShowStat );
+
+    # Plugin correctly initialized
+    return 1;
+}
+
+sub StrToIp{
+return unpack('N',pack('C4',split(/\./,$_[0])));
+}
+
+sub _ShowStat {
+my($session, $params, $theTopic, $theWeb) = @_;
+
+### parameters
+my $host = $params->{_DEFAULT} || $params->{host};
+return "" if (!$host);
+
+my $host_aton=StrToIp($host);
+my $SQL = "SELECT A.id, A.ip, A.mac, L.login, A.nagios, A.dhcp_hostname, A.enabled, G.group_name, Q.queue_name,
+A.last_found, A.comments FROM User_auth as A, User_list as L, Group_list as G, Queue_list As Q
+WHERE A.user_id = L.id and A.filter_group_id = G.id and Q.id = A.queue_id AND A.deleted =0 and A.ip_int=".$host_aton." LIMIT 1";
+
+my $dbh = DBI->connect("dbi:$dbstat->{driver}:database=$dbstat->{database};host=$dbstat->{hostname}","$dbstat->{username}","$dbstat->{password}");
+my $status = '';
+eval {
+if ( !defined $dbh ) { return "Cannot connect to mySQL server: $DBI::errstr\n"; }
+$dbh->do('SET NAMES utf8');
+$dbh->{'mysql_enable_utf8'} = 1;
+my $sth = $dbh->prepare($SQL);
+$sth->execute;
+my $res = $sth->fetchrow_hashref();
+if ($res) {
+
+    my $cSQL = "SELECT * FROM `config` WHERE option_id=";
+    my $sth1 = $dbh->prepare($SQL."57");
+    $sth1->execute;
+    my $nagios_row = $sth1->fetchrow_hashref();
+    my $nagios_url;
+    if ($nagios_row) { $nagios_url = $nagios_row->{value}."/cgi-bin/status.cgi?navbarsearch=1&host=".$host; }
+
+    $sth1 = $dbh->prepare($SQL."62");
+    $sth1->execute;
+    my $stat_row = $sth1->fetchrow_hashref();
+    my $stat_url;
+    if ($stat_row) { $stat_url = $stat_row->{value}."/admin/users/editauth.php?id=".$res->{id}; }
+
+    $status.='<div style="margin: 0 auto;">';
+    $status.='<div style="float: left;">';
+    $status.='Ссылки на внешние ресурсы<br>';
+    $status.='<a href="'.$nagios_url.'">Nagios</a><br>' if ($nagios_url and $res->{nagios});
+    $status.='<a href="'.$stat_url.'">Stat</a><br>' if ($stat_url);
+
+    $status.='</div>';
+    $status.='<div style="float: right; width: 200px;">';
+    $status.='Login: '.$res->{login}.'<br>';
+    if ($res->{enabled}) { $status.='Включен: Да<br>'; } else { $status.='Включен: Нет<br>'; }
+    if ($res->{nagios}) { $status.='Nagios: Да<br>'; } else { $status.='Nagios: Нет<br>'; }
+    $status.='Dhcp hostname: '.$res->{dhcp_hostname}.'<br>' if ($res->{dhcp_hostname});
+    $status.='Фильтр: '.$res->{group_name}.'<br>';
+    $status.='Шейпер: '.$res->{queue_name}.'<br>';
+    $status.='Комментарий: '.$res->{comments}.'<br>';
+    $status.='last found: '.$res->{last_found}.'<br>' if ($res->{last_found});
+    $status.='</div>';
+    $status.='</div>';
+    $status.='<div style="clear: left;"><p></p></div>';
+    }
+};
+if ($@) { return "DBI error: $@"; }
+return $status;
+}
+
+1;

+ 128 - 0
docs/wiki/foswiki/StatSyncPlugin.pm

@@ -0,0 +1,128 @@
+package Foswiki::Plugins::StatSyncPlugin;
+
+# Always use strict to enforce variable scoping
+use strict;
+use utf8;
+
+use DBI;
+use Data::Dumper;
+
+# $VERSION is referred to by Foswiki, and is the only global variable that
+# *must* exist in this package
+use vars qw( $VERSION $RELEASE $debug $dbstat $pluginName );
+
+use Foswiki::Func    ();    # The plugins API
+use Foswiki::Plugins ();    # For the API version
+
+# This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
+# status of the plugin. It is used by the build automation tools, so
+# you should leave it alone.
+$VERSION = '$Rev: 8713$';
+
+# This is a free-form string you can use to "name" your own plugin version.
+# It is *not* used by the build automation tools, but is reported as part
+# of the version number in PLUGINDESCRIPTIONS.
+$RELEASE = '1.01';
+
+# Name of this Plugin, only used in this module
+$pluginName = 'StatSyncPlugin';
+
+=pod
+
+---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
+   * =$topic= - the name of the topic in the current CGI query
+   * =$web= - the name of the web in the current CGI query
+   * =$user= - the login name of the user
+   * =$installWeb= - the name of the web the plugin is installed in
+
+REQUIRED
+
+Called to initialise the plugin. If everything is OK, should return
+a non-zero value. On non-fatal failure, should write a message
+using Foswiki::Func::writeWarning and return 0. In this case
+%FAILEDPLUGINS% will indicate which plugins failed.
+
+In the case of a catastrophic failure that will prevent the whole
+installation from working safely, this handler may use 'die', which
+will be trapped and reported in the browser.
+
+You may also call =Foswiki::Func::registerTagHandler= here to register
+a function to handle tags that have standard Foswiki syntax - for example,
+=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
+Foswiki tag handling functions this way, though this practice is unsupported
+and highly dangerous!
+
+=cut
+
+sub initPlugin {
+    my( $topic, $web ) = @_;
+
+    # check for Plugins.pm versions
+    if( $Foswiki::Plugins::VERSION < 1.026 ) {
+        Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
+        return 0;
+        }
+
+    return 0 unless $Foswiki::cfg{Plugins}{DatabasePlugin}{ConfigSource};
+    if ( $Foswiki::cfg{Plugins}{DatabasePlugin}{ConfigSource} eq 'Local' ) {
+        foreach  my $info ( @{ $Foswiki::cfg{Plugins}{DatabasePlugin}{Databases} } ) {
+            next if ($info->{description} ne "stat");
+            $dbstat = $info;
+            last;
+            }
+      }
+
+    return 0 if (!$dbstat);
+
+    # register the _EXAMPLETAG function to handle %EXAMPLETAG{...}%
+    Foswiki::Func::registerTagHandler( 'STATSYNC', \&_STATSYNC );
+
+    # Plugin correctly initialized
+    return 1;
+}
+
+sub StrToIp{
+return unpack('N',pack('C4',split(/\./,$_[0])));
+}
+
+sub _STATSYNC {
+my($session, $params, $theTopic, $theWeb) = @_;
+
+### parameters
+my $host = $params->{_DEFAULT} || $params->{host};
+my $dnsname = $params->{dnsname};
+my $comment = $params->{comment};
+my $wikiname = $params->{wikiname};
+
+return "" if (!$host);
+
+my $host_aton=StrToIp($host);
+my $SQL = "SELECT id,dns_name,WikName,comments FROM User_auth WHERE ip_int=".$host_aton." and deleted=0 LIMIT 1";
+my $dbh = DBI->connect("dbi:$dbstat->{driver}:database=$dbstat->{database};host=$dbstat->{hostname}","$dbstat->{username}","$dbstat->{password}");
+eval {
+if ( !defined $dbh ) { return "Cannot connect to mySQL server: $DBI::errstr\n"; }
+$dbh->do('SET NAMES utf8');
+$dbh->{'mysql_enable_utf8'} = 1;
+my $sth = $dbh->prepare($SQL);
+$sth->execute;
+my $res = $sth->fetchrow_hashref();
+if ($res) {
+    if ($dnsname and $res->{dns_name} ne $dnsname) {
+        $sth = $dbh->prepare("UPDATE User_auth SET dns_name='".$dnsname."' WHERE id=".$res->{id});
+        $sth->execute;
+        }
+    if ($comment and $res->{comments} ne $comment) {
+        $sth = $dbh->prepare("UPDATE User_auth SET comments='".$comment."' WHERE id=".$res->{id});
+        $sth->execute;
+        }
+    if ($wikiname and $res->{WikiName} ne $wikiname) {
+        $sth = $dbh->prepare("UPDATE User_auth SET WikiName='".$wikiname."' WHERE id=".$res->{id});
+        $sth->execute;
+        }
+    }
+};
+if ($@) { return "DBI error: $@"; }
+return "";
+}
+
+1;

+ 270 - 0
docs/wiki/foswiki/UpsInfoPlugin.pm

@@ -0,0 +1,270 @@
+package Foswiki::Plugins::UpsInfoPlugin;
+
+use Net::SNMP;
+use Net::Ping;
+
+# Always use strict to enforce variable scoping
+use strict;
+
+# $VERSION is referred to by Foswiki, and is the only global variable that
+# *must* exist in this package
+use vars qw( $VERSION $RELEASE $debug $pluginName );
+
+use Foswiki::Func    ();    # The plugins API
+use Foswiki::Plugins ();    # For the API version
+
+# This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
+# status of the plugin. It is used by the build automation tools, so
+# you should leave it alone.
+$VERSION = '$Rev: 8713$';
+
+# This is a free-form string you can use to "name" your own plugin version.
+# It is *not* used by the build automation tools, but is reported as part
+# of the version number in PLUGINDESCRIPTIONS.
+$RELEASE = '1.01';
+
+# Name of this Plugin, only used in this module
+$pluginName = 'UpsInfoPlugin';
+
+=pod
+
+---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
+   * =$topic= - the name of the topic in the current CGI query
+   * =$web= - the name of the web in the current CGI query
+   * =$user= - the login name of the user
+   * =$installWeb= - the name of the web the plugin is installed in
+
+REQUIRED
+
+Called to initialise the plugin. If everything is OK, should return
+a non-zero value. On non-fatal failure, should write a message
+using Foswiki::Func::writeWarning and return 0. In this case
+%FAILEDPLUGINS% will indicate which plugins failed.
+
+In the case of a catastrophic failure that will prevent the whole
+installation from working safely, this handler may use 'die', which
+will be trapped and reported in the browser.
+
+You may also call =Foswiki::Func::registerTagHandler= here to register
+a function to handle tags that have standard Foswiki syntax - for example,
+=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
+Foswiki tag handling functions this way, though this practice is unsupported
+and highly dangerous!
+
+=cut
+
+sub initPlugin {
+    my( $topic, $web, $user, $installWeb ) = @_;
+
+    # check for Plugins.pm versions
+    if( $Foswiki::Plugins::VERSION < 1.026 ) {
+        Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
+        return 0;
+    }
+
+    Foswiki::Func::registerTagHandler( 'UpsINFO', \&_UpsINFO );
+
+    # Plugin correctly initialized
+    return 1;
+}
+
+sub GetSNMPkeyValue {
+my $session = shift;
+my $key = shift;
+my $value;
+eval {
+my $ret = $session->get_request( -varbindlist => [$key] );
+if (!$ret) {
+    #search in subtree
+    $ret = $session->get_next_request( -varbindlist => [$key] );
+    my $branch = $key.'.*';
+    my @keys_next = keys %$ret;
+    my $get_key = $keys_next[0];
+    if ($get_key=~/^$branch$/) { $value = $ret->{$get_key}; }
+    } else { $value = $ret->{$key}; }
+};
+return $value;
+};
+
+sub _UpsINFO {
+    my($session, $params, $theTopic, $theWeb) = @_;
+    # $session  - a reference to the Foswiki session object (if you don't know
+    #             what this is, just ignore it)
+    # $params=  - a reference to a Foswiki::Attrs object containing parameters.
+    #             This can be used as a simple hash that maps parameter names
+    #             to values, with _DEFAULT being the name for the default
+    #             parameter.
+    # $theTopic - name of the topic in the query
+    # $theWeb   - name of the web in the query
+    # Return: the result of processing the tag
+
+    # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
+    # $params->{_DEFAULT} will be 'hamburger'
+    # $params->{sideorder} will be 'onions'
+
+my $OIDModel       = '.1.3.6.1.2.1.33.1.1.1.0';
+my $SchneiderModel = '.1.3.6.1.2.1.1.1.0';
+
+# APC OIDs
+my $OIDAPC                = '1.3.6.1.4.1.318.';
+my $OIDhardware           = '1.3.6.1.4.1.318.1.1.';
+my $OIDups                = '1.3.6.1.4.1.318.1.1.1.';
+my $OIDident              = '1.3.6.1.4.1.318.1.1.1.1.';
+my $OIDidentBasic         = '1.3.6.1.4.1.318.1.1.1.1.1.';
+my $OIDidentBasicModel    = '1.3.6.1.4.1.318.1.1.1.1.1.1.0';
+my $OIDidentBasicName     = '1.3.6.1.4.1.318.1.1.1.1.1.2.0';
+my $OIDidentAdv           = '1.3.6.1.4.1.318.1.1.1.1.2.';
+my $OIDidentAdvFW         = '1.3.6.1.4.1.318.1.1.1.1.2.1.0';
+my $OIDidentAdvManuf      = '1.3.6.1.4.1.318.1.1.1.1.2.2.0';
+my $OIDidentAdvSerial     = '1.3.6.1.4.1.318.1.1.1.1.2.3.0';
+my $OIDbattery            = '1.3.6.1.4.1.318.1.1.1.2.';
+my $OIDbatteryBasic       = '1.3.6.1.4.1.318.1.1.1.2.1.';
+my $OIDbatteryBasicStatus = '1.3.6.1.4.1.318.1.1.1.2.1.1.0';
+my $OIDbatteryBasicTime   = '1.3.6.1.4.1.318.1.1.1.2.1.2.0';
+my $OIDbatteryBasicRepl   = '1.3.6.1.4.1.318.1.1.1.2.1.3.0';
+my $OIDbatteryAdv         = '1.3.6.1.4.1.318.1.1.1.2.2.';
+my $OIDbatteryAdvTemp     = '1.3.6.1.4.1.318.1.1.1.2.2.2.0';
+my $OIDbatteryAdvRuntime  = '1.3.6.1.4.1.318.1.1.1.2.2.3.0';
+my $OIDbatteryAdvReplace  = '1.3.6.1.4.1.318.1.1.1.2.2.4.0';
+
+my $apcUpsAdvBatteryStatus              ='1.3.6.1.4.1.318.1.1.1.4.1.1.0';
+my $apcUpsAdvBatteryCapacity            ='1.3.6.1.4.1.318.1.1.1.2.2.1.0';
+my $apcUpsAdvBatteryTemperature         ='1.3.6.1.4.1.318.1.1.1.2.2.2.0';
+my $apcUpsAdvBatteryRunTimeRemaining    ='1.3.6.1.4.1.318.1.1.1.2.2.3.0';
+my $apcUpsAdvOutputVoltage              ='1.3.6.1.4.1.318.1.1.1.4.2.1.0';
+my $apcUpsAdvOutputFrequency            ='1.3.6.1.4.1.318.1.1.1.4.2.2.0';
+my $apcUpsAdvOutputLoad                 ='1.3.6.1.4.1.318.1.1.1.4.2.3.0';
+my $apcUpsAdvOutputCurrent              ='1.3.6.1.4.1.318.1.1.1.4.2.4.0';
+my $apcUpsAdvInputLineVoltage           ='1.3.6.1.4.1.318.1.1.1.3.2.1.0';
+my $apcUpsAdvInputFrequency             ='1.3.6.1.4.1.318.1.1.1.3.2.4.0';
+
+my $BATTERYREPLACE = '2';
+
+my $defaultModel          = '.1.3.6.1.2.1.33.1.1.2.0';
+my $defaultBatteryReplace;
+my $defaultBatteryStatus  = '.1.3.6.1.2.1.33.1.2.1';
+my $defaultbatteryTemp    = '.1.3.6.1.2.1.33.1.2.4';
+my $defaultInputAC        = '.1.3.6.1.2.1.33.1.3.3.1.3.1';
+my $defaultInputHz        = '.1.3.6.1.2.1.33.1.3.3.1.2';
+my $defaultOutputAC       = '.1.3.6.1.2.1.33.1.4.4.1.2';
+my $defaultOutputCurrent  = '.1.3.6.1.2.1.33.1.4.4.1.3';
+my $defaultOutputPower    = '.1.3.6.1.2.1.33.1.4.4.1.4';
+my $defaultPercentLoad    = '.1.3.6.1.2.1.33.1.4.4.1.5';
+my $defaultLiveTime       = '.1.3.6.1.2.1.33.1.2.3';
+my $defaultUpsLoad        = '.1.3.6.1.2.1.33.1.4.4.1.5.1';
+my $defaultUpsStatus      = '.1.3.6.1.2.1.33.1.6.3.2';
+my $defaultOutputHz       = '.1.3.6.1.2.1.33.1.4.2';
+
+my $TEMPCRIT = 55;
+my $TEMPWARN = 50;
+
+    my $host = $params->{_DEFAULT} || $params->{host};
+
+    ### check host alive
+    my $p = Net::Ping->new("tcp",1,1);
+    my $ok= $p->ping($host);
+    $p->close();
+
+    if (!$ok) {  return "Ups $host is not available<BR>"; }
+
+    undef($p);
+
+    my $port = $params->{port} || 161;
+    my $timeout = $params->{timeout} || 5;
+
+    my $community = $params->{community};
+    $community =  'public' if (!$community);
+
+    my $snmp_session;
+    my $error;
+
+    ### open SNMP session
+    eval {
+    ($snmp_session, $error) = Net::SNMP->session( -hostname  => $host, -community => $community );
+    };
+
+    return "Ups is not available<BR>"  if (!defined($snmp_session));
+
+    $snmp_session->translate([-timeticks]);
+
+    my $vendor;
+    my $vendor_string = GetSNMPkeyValue($snmp_session,$OIDModel);
+    if (!$vendor_string) { $vendor_string = GetSNMPkeyValue($snmp_session,$SchneiderModel); $vendor = 'Schneider'; }
+    return "Ups model unknown!<BR>"  if (!defined($vendor_string));
+
+    if (!$vendor and $vendor_string=~/Eaton/i) { $vendor='EATON'; }
+    if (!$vendor and $vendor_string=~/APC/i) { $vendor='APC'; }
+
+    my $upsModel = GetSNMPkeyValue($snmp_session,$defaultModel);
+
+    my $ret = "UPS Model: ".$upsModel."\n\n";
+
+    my $battery_status = GetSNMPkeyValue($snmp_session,$defaultBatteryStatus);
+    my $input_voltage = GetSNMPkeyValue($snmp_session,$defaultInputAC);
+
+    my $status = "%GREEN%ONLINE%ENDCOLOR%";
+    $status = "%RED%AHEZ%ENDCOLOR%" if ($battery_status eq 1);
+    $status = "%RED%ON BATTERY%ENDCOLOR%" if ($battery_status eq 3);
+    $status = "%RED%On Smart Boost%ENDCOLOR%" if ($battery_status eq 4);
+    $status = "%RED%Timed Sleeping%ENDCOLOR%" if ($battery_status eq 5);
+    $status = "%RED%Software Bypass%ENDCOLOR%" if ($battery_status eq 6);
+    $status = "%RED%OFF%ENDCOLOR%" if ($battery_status eq 7);
+    $status = "%GREEn%REBOOTING%ENDCOLOR%" if ($battery_status eq 8);
+    $status = "%RED%SWITCHED BYPASS%ENDCOLOR%" if ($battery_status eq 9);
+    $status = "%RED%Hardware Failure Bypass%ENDCOLOR%" if ($battery_status eq 10);
+    $status = "%RED%Sleeping until power return%ENDCOLOR%" if ($battery_status eq 11);
+    $ret .= "| UPS Status | ".$status." |\n";
+
+    if ($vendor eq 'APC') {
+        my $batteryAdvReplace = $snmp_session->get_request(-varbindlist => [$OIDbatteryAdvReplace])->{$OIDbatteryAdvReplace};
+        if ($batteryAdvReplace && ($batteryAdvReplace eq $BATTERYREPLACE)) { $ret .= "| Battery Status | %RED%Battery requires replacement!%ENDCOLOR%|\n"; };
+        $ret .= "| Battery Capacity | ".$snmp_session->get_request(-varbindlist => [$apcUpsAdvBatteryCapacity])->{$apcUpsAdvBatteryCapacity}."% |\n";
+        }
+
+    my $inputHz = GetSNMPkeyValue($snmp_session,$defaultInputHz);
+    if ($inputHz) { $inputHz = int($inputHz/10); }
+    my $outputHz = GetSNMPkeyValue($snmp_session,$defaultOutputHz);
+    if ($outputHz) { $outputHz = int($outputHz/10); }
+    my $runtime;
+
+    if ($vendor eq 'APC') {
+        $runtime = GetSNMPkeyValue($snmp_session,$OIDbatteryAdvRuntime);
+        $runtime=int($runtime/6000);
+        } else {
+        if ($vendor eq 'EATON') {
+            $runtime = GetSNMPkeyValue($snmp_session,'.1.3.6.1.4.1.534.1.2.1');
+            } else {
+            $runtime = GetSNMPkeyValue($snmp_session,$defaultLiveTime);
+            }
+        }
+    if ($vendor eq 'EATON') { $runtime=int($runtime/60); }
+    my $outputCurrent = GetSNMPkeyValue($snmp_session,$defaultOutputCurrent);
+    if ($outputCurrent) { $outputCurrent=$outputCurrent/10; }
+
+    my $batTemp;
+    if ($vendor eq 'APC') {
+        $batTemp=GetSNMPkeyValue($snmp_session,$OIDbatteryAdvTemp);
+        } else {
+        if ($vendor eq 'EATON') {
+            $batTemp=GetSNMPkeyValue($snmp_session,'.1.3.6.1.4.1.534.1.6.1.0');
+            } else {
+            $batTemp=GetSNMPkeyValue($snmp_session,$defaultbatteryTemp);
+            }
+        }
+
+    $ret .= "| Runtime Remaining | ". $runtime." min. |\n";
+    $ret .= "| Battery Temperature | ".$batTemp." C |\n";
+    $ret .= "| Output Voltage | ".GetSNMPkeyValue($snmp_session,$defaultOutputAC)." |\n";
+    $ret .= "| Output Frequency | ".$outputHz." Hz |\n";
+    $ret .= "| Output Load | ".GetSNMPkeyValue($snmp_session,$defaultUpsLoad)." % |\n";
+    $ret .= "| Output Current | ".$outputCurrent."  A |\n";
+    $ret .= "| Input Voltage | ".$input_voltage." V |\n";
+    $ret .= "| Input Frequency | ".$inputHz." Hz |\n";
+
+    $snmp_session->close;
+
+    return $ret;
+}
+
+
+1;

+ 442 - 0
docs/wiki/foswiki/WlcInfoPlugin.pm

@@ -0,0 +1,442 @@
+package Foswiki::Plugins::WlcInfoPlugin;
+
+use utf8;
+use Net::SNMP qw(:snmp ticks_to_time TRANSLATE_NONE);
+use Net::Ping;
+
+# Always use strict to enforce variable scoping
+use strict;
+
+# $VERSION is referred to by Foswiki, and is the only global variable that
+# *must* exist in this package
+use vars qw( $VERSION $RELEASE $debug $pluginName );
+
+use Foswiki::Func    ();    # The plugins API
+use Foswiki::Plugins ();    # For the API version
+
+# This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
+# status of the plugin. It is used by the build automation tools, so
+# you should leave it alone.
+$VERSION = '$Rev: 8713$';
+
+# This is a free-form string you can use to "name" your own plugin version.
+# It is *not* used by the build automation tools, but is reported as part
+# of the version number in PLUGINDESCRIPTIONS.
+$RELEASE = '1.01';
+
+# Name of this Plugin, only used in this module
+$pluginName = 'WlcInfoPlugin';
+
+=pod
+
+---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
+   * =$topic= - the name of the topic in the current CGI query
+   * =$web= - the name of the web in the current CGI query
+   * =$user= - the login name of the user
+   * =$installWeb= - the name of the web the plugin is installed in
+
+REQUIRED
+
+Called to initialise the plugin. If everything is OK, should return
+a non-zero value. On non-fatal failure, should write a message
+using Foswiki::Func::writeWarning and return 0. In this case
+%FAILEDPLUGINS% will indicate which plugins failed.
+
+In the case of a catastrophic failure that will prevent the whole
+installation from working safely, this handler may use 'die', which
+will be trapped and reported in the browser.
+
+You may also call =Foswiki::Func::registerTagHandler= here to register
+a function to handle tags that have standard Foswiki syntax - for example,
+=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
+Foswiki tag handling functions this way, though this practice is unsupported
+and highly dangerous!
+
+=cut
+
+sub initPlugin {
+    my( $topic, $web, $user, $installWeb ) = @_;
+
+    # check for Plugins.pm versions
+    if( $Foswiki::Plugins::VERSION < 1.026 ) {
+        Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
+        return 0;
+    }
+
+    Foswiki::Func::registerTagHandler( 'WlcINFO', \&_WlcINFO );
+
+    # Plugin correctly initialized
+    return 1;
+}
+
+sub StrToIp{
+return unpack('N',pack('C4',split(/\./,$_[0])));
+}
+
+sub extract_dec_mac {
+my $base_oid = shift;
+my $key = shift;
+$key =~s/^$base_oid\.//;
+return $key;
+}
+
+sub mac_splitted{
+my $mac=shift;
+return if (!$mac);
+my $ch=shift || ":";
+$mac=~s/(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})/$1:$2:$3:$4:$5:$6/g;
+if ($ch ne ":") { $mac=~s/\:/$ch/g; }
+return $mac;
+}
+
+sub dec2mac {
+my $key = shift;
+my @dec_mac = split(/\./,$key);
+my @mac=();
+for (my $i = 0; $i < scalar(@dec_mac); $i++) { $mac[$i]=sprintf("%02x",$dec_mac[$i]); }
+$key = join(':',@mac);
+return $key;
+}
+
+sub expand_status {
+my ($client,$filter) = @_;
+my $ret ='';
+foreach my $id (sort keys %$client) {
+        next if ($filter and $client->{$id}->{mac} ne $filter);
+        $ret.='| '.$client->{$id}->{ap_id}.' | ';
+        $ret.=$client->{$id}->{ap_mac}.' | ';
+        $ret.=$client->{$id}->{sid}.' | ';
+        $ret.=$client->{$id}->{mac}.' | ';
+        if (!$client->{$id}->{ip}) { $client->{$id}->{ip}='0.0.0.0'; }
+        $ret.=$client->{$id}->{ip}.' | ';
+        $ret.=$client->{$id}->{Hz}.' | ';
+        $ret.=$client->{$id}->{ch}.' | ';
+        $ret.=$client->{$id}->{rx}.'/'.$client->{$id}->{tx}.' | ';
+        $ret.=$client->{$id}->{band}.' | ';
+        $ret.=$client->{$id}->{uptime}." |\n";
+        }
+return $ret;
+};
+
+sub table_callback {
+my ($session, $OID_ifTable, $table) = @_;
+
+my $list = $session->var_bind_list();
+if (!defined $list) {
+    printf "ERROR: %s\n", $session->error();
+    return;
+    }
+
+my @names = $session->var_bind_names();
+my $next  = undef;
+
+while (@names) {
+   $next = shift @names;
+   if (!oid_base_match($OID_ifTable, $next)) {
+      return; # Table is done.
+      }
+   $table->{$next} = $list->{$next};
+}
+
+my $result = $session->get_bulk_request( -varbindlist => [ $next ], -maxrepetitions => 10, );
+if (!defined $result) { printf "ERROR: %s.\n", $session->error(); }
+return;
+}
+
+sub _WlcINFO {
+my($session, $params, $theTopic, $theWeb) = @_;
+
+my $host = $params->{_DEFAULT} || $params->{host};
+
+### check host alive
+my $p = Net::Ping->new("tcp",1,1);
+my $ok= $p->ping($host);
+$p->close();
+if (!$ok) {  return "Ups $host is not available<BR>"; }
+
+undef($p);
+
+my $port = $params->{port} || 161;
+my $timeout = $params->{timeout} || 5;
+
+my $community = $params->{community};
+$community =  'public' if (!$community);
+
+#1 - client list
+#2 - mac list
+#3 - ssid list
+#4 - ip list
+
+my $mode = $params->{mode} || '3';
+my $filter = $params->{filter};
+
+my $snmp_session;
+my $error;
+
+my %DefaultMibs=(
+'Description'    => '.1.3.6.1.2.1.1.1.0',
+'Uptime'         => '.1.3.6.1.2.1.1.3.0',
+'Name'           => '.1.3.6.1.2.1.1.5.0',
+);
+
+my %HuaweiWlcMibs=(
+#'ClientList'     =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.2',
+'ClientAPHexList'=>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.3',
+#'ClientAPList'   =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.4',
+#dec-mac = string
+#'APVap'=>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.5',
+#dec-mac = на какой диапазон подкючен клиент 1 - 2.4G 2 - 5G
+'ClientHz'       =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.7',
+'ClientChannel'  =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.9',
+# - полоса - INTEGER{invalid(1),ht40(2),ht20(3),vht80(4)}
+'ClientBand'     =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.11',
+'ClientRxRate'   =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.14',
+'ClientTxRate'   =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.15',
+'ClientSSID'     =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.16',
+'ClientIp'       =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.25',
+'ClientUptime'   =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.30',
+'ClientApId'     =>'.1.3.6.1.4.1.2011.6.139.18.1.2.1.53',
+);
+
+### open SNMP session
+eval {
+    ($snmp_session, $error) = Net::SNMP->session(
+    -hostname  => $host,
+    -community => $community,
+    -nonblocking => 1,
+    -translate   => [-octetstring => 0],
+    -version     => 'snmpv2c',
+    );
+};
+
+return "Wlc is not available<BR>"  if (!defined($snmp_session));
+
+$snmp_session->translate([-timeticks]);
+
+my %defaultTable;
+my $ret = $snmp_session->get_bulk_request(
+    -varbindlist    => [ '.1.3.6.1.2.1.1' ],
+    -callback       => [ \&table_callback, '.1.3.6.1.2.1.1', \%defaultTable ],
+    -maxrepetitions => 10,
+    );
+
+if (!defined $ret) {
+    $snmp_session->close();
+    return "Wlc not answer!<BR>";
+    }
+# Now initiate the SNMP message exchange.
+snmp_dispatcher();
+
+my %wlcTable;
+
+foreach my $key (keys %HuaweiWlcMibs) {
+my $huawei_wlc_mib = $HuaweiWlcMibs{$key};
+my %table;
+my $result = $snmp_session->get_bulk_request(
+    -varbindlist    => [ $huawei_wlc_mib ],
+    -callback       => [ \&table_callback, $huawei_wlc_mib, \%table ],
+    -maxrepetitions => 10,
+    );
+if (!defined $result) {
+    printf "ERROR: %s\n", $snmp_session->error();
+    $snmp_session->close();
+    exit 1;
+    }
+# Now initiate the SNMP message exchange.
+snmp_dispatcher();
+$wlcTable{$key}=\%table;
+}
+
+$snmp_session->close();
+
+my $result=$defaultTable{$DefaultMibs{Name}}."\n<br>";
+$result.=$defaultTable{$DefaultMibs{Description}}."\n<br>";
+my $uptime = int($defaultTable{$DefaultMibs{Uptime}}/100);
+my $day; my $hour; my $min;
+$day = int($uptime/86400);
+$hour = int(($uptime - 86400*$day)/3600);
+$min = int (($uptime - 86400*$day - 3600*$hour)/60);
+my $s_uptime = "$day days $hour:$min";
+$result.= "$s_uptime\n<br>\n";
+
+my %client_status;
+
+my $key = 'ClientApId';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $ap_id = $wlcTable{$key}->{$oid};
+$client_status{$dec_mac}->{mac}=dec2mac($dec_mac);
+$client_status{$dec_mac}->{ap_id}=$ap_id;
+}
+$key = 'ClientAPHexList';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $ap_mac = mac_splitted(unpack('H*',$wlcTable{$key}->{$oid}));
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{ap_mac}=$ap_mac;
+}
+$key = 'ClientHz';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $Hz = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+if ($Hz eq '1') { $Hz='2.4G'; }
+if ($Hz eq '2') { $Hz='5G'; }
+$client_status{$dec_mac}->{Hz}=$Hz;
+}
+$key = 'ClientChannel';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $ch = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{ch}=$ch;
+}
+$key = 'ClientBand';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $band = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+if ($band eq '1') { $band = '10M'; }
+if ($band eq '2') { $band = '40M'; }
+if ($band eq '3') { $band = '20M'; }
+if ($band eq '4') { $band = '80M'; }
+$client_status{$dec_mac}->{band}=$band;
+}
+$key = 'ClientRxRate';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $rx = $wlcTable{$key}->{$oid};
+if ($rx eq '65535') { $rx = 0; }
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{rx}=$rx;
+}
+$key = 'ClientTxRate';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $tx = $wlcTable{$key}->{$oid};
+if ($tx eq '65535') { $tx = 0; }
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{tx}=$tx;
+}
+$key = 'ClientSSID';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $SSID = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{sid}=$SSID;
+}
+$key = 'ClientIp';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $ip = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+$client_status{$dec_mac}->{ip}=$ip;
+}
+$key = 'ClientUptime';
+for my $oid (oid_lex_sort(keys %{$wlcTable{$key}})) {
+my $dec_mac = extract_dec_mac($HuaweiWlcMibs{$key},$oid);
+my $uptime = $wlcTable{$key}->{$oid};
+my $ap_id = $client_status{$dec_mac}->{ap_id};
+my $day; my $hour; my $min;
+$day = int($uptime/86400);
+$hour = int(($uptime - 86400*$day)/3600);
+$min = int (($uptime - 86400*$day - 3600*$hour)/60);
+my $s_uptime = "$day days $hour:$min";
+$client_status{$dec_mac}->{uptime}=$s_uptime;
+}
+
+my %wlc_status;
+my $all_clients=0;
+foreach my $dec_mac (sort keys %client_status) {
+my $ssid = $client_status{$dec_mac}->{sid};
+if (!exists($wlc_status{$ssid})) { $wlc_status{$ssid}{count}=0; $wlc_status{$ssid}{count2}=0; $wlc_status{$ssid}{count5}=0; }
+$wlc_status{$ssid}{count}++;
+$all_clients++;
+if ($client_status{$dec_mac}->{Hz} eq '5G') { $wlc_status{$ssid}{count5}++; } else { $wlc_status{$ssid}{count2}++; }
+}
+
+$result.="\n<br>Wireless counters:\n<br>\n";
+$result.="| *SSID* | *Count* | *2.4G* | *5G* |\n";
+foreach my $ssid (sort keys %wlc_status) {
+$result.= "| $ssid | $wlc_status{$ssid}{count} | $wlc_status{$ssid}{count2} | $wlc_status{$ssid}{count5} |\n";
+}
+$result.= "\n<br>Total: $all_clients\n<br>\n";
+
+$result.= "| *AP id* | *AP* | *SSID* | *Client* | *IP* | *Hz* | *Channel* | *Rx/Tx* | *Band* | *Uptime* |\n";
+
+if ($mode eq '1') { $result.=expand_status(\%client_status,$filter); }
+
+if ($mode eq '2') {
+    my %ap_status;
+    foreach my $dec_mac (sort keys %client_status) {
+        if (!$client_status{$dec_mac}->{ip}) { $client_status{$dec_mac}->{ip}='0.0.0.0'; }
+        my $ap_id = $client_status{$dec_mac}->{ap_id};
+        $ap_status{$ap_id}->{$dec_mac}->{ap_id}=$ap_id;
+        $ap_status{$ap_id}->{$dec_mac}->{ap_mac}=$client_status{$dec_mac}->{ap_mac};
+        $ap_status{$ap_id}->{$dec_mac}->{sid}=$client_status{$dec_mac}->{sid};
+        $ap_status{$ap_id}->{$dec_mac}->{mac}=$client_status{$dec_mac}->{mac};
+        $ap_status{$ap_id}->{$dec_mac}->{ip}=$client_status{$dec_mac}->{ip};
+        $ap_status{$ap_id}->{$dec_mac}->{Hz}=$client_status{$dec_mac}->{Hz};
+        $ap_status{$ap_id}->{$dec_mac}->{ch}=$client_status{$dec_mac}->{ch};
+        $ap_status{$ap_id}->{$dec_mac}->{rx}=$client_status{$dec_mac}->{rx};
+        $ap_status{$ap_id}->{$dec_mac}->{tx}=$client_status{$dec_mac}->{tx};
+        $ap_status{$ap_id}->{$dec_mac}->{band}=$client_status{$dec_mac}->{band};
+        $ap_status{$ap_id}->{$dec_mac}->{uptime}=$client_status{$dec_mac}->{uptime};
+        }
+    foreach my $ap_id (sort {$a <=> $b} keys %ap_status) {
+        next if ($filter and $ap_id ne $filter);
+        $result.=expand_status($ap_status{$ap_id});
+        }
+    }
+
+if ($mode eq '3') {
+    my %ssid_status;
+    foreach my $dec_mac (sort keys %client_status) {
+        if (!$client_status{$dec_mac}->{ip}) { $client_status{$dec_mac}->{ip}='0.0.0.0'; }
+        my $ssid = $client_status{$dec_mac}->{sid};
+        $ssid_status{$ssid}->{$dec_mac}->{ap_id}=$client_status{$dec_mac}->{ap_id};
+        $ssid_status{$ssid}->{$dec_mac}->{ap_mac}=$client_status{$dec_mac}->{ap_mac};
+        $ssid_status{$ssid}->{$dec_mac}->{sid}=$ssid;
+        $ssid_status{$ssid}->{$dec_mac}->{mac}=$client_status{$dec_mac}->{mac};
+        $ssid_status{$ssid}->{$dec_mac}->{ip}=$client_status{$dec_mac}->{ip};
+        $ssid_status{$ssid}->{$dec_mac}->{Hz}=$client_status{$dec_mac}->{Hz};
+        $ssid_status{$ssid}->{$dec_mac}->{ch}=$client_status{$dec_mac}->{ch};
+        $ssid_status{$ssid}->{$dec_mac}->{rx}=$client_status{$dec_mac}->{rx};
+        $ssid_status{$ssid}->{$dec_mac}->{tx}=$client_status{$dec_mac}->{tx};
+        $ssid_status{$ssid}->{$dec_mac}->{band}=$client_status{$dec_mac}->{band};
+        $ssid_status{$ssid}->{$dec_mac}->{uptime}=$client_status{$dec_mac}->{uptime};
+        }
+    foreach my $ssid (sort {$a <=> $b} keys %ssid_status) {
+        next if ($filter and $ssid ne $filter);
+        $result.=expand_status($ssid_status{$ssid});
+        }
+    }
+
+if ($mode eq '4') {
+    my %ip_status;
+    my $unknown_count=0;
+    foreach my $dec_mac (sort keys %client_status) {
+        my $ip;
+        if (!$client_status{$dec_mac}->{ip}) { $ip=$unknown_count; $unknown_count++; } else { $ip = StrToIp($client_status{$dec_mac}->{ip}); }
+        $ip_status{$ip}->{$dec_mac}->{ap_id}=$client_status{$dec_mac}->{ap_id};;
+        $ip_status{$ip}->{$dec_mac}->{ap_mac}=$client_status{$dec_mac}->{ap_mac};
+        $ip_status{$ip}->{$dec_mac}->{sid}=$client_status{$dec_mac}->{sid};
+        $ip_status{$ip}->{$dec_mac}->{mac}=$client_status{$dec_mac}->{mac};
+        $ip_status{$ip}->{$dec_mac}->{ip}=$client_status{$dec_mac}->{ip};
+        $ip_status{$ip}->{$dec_mac}->{Hz}=$client_status{$dec_mac}->{Hz};
+        $ip_status{$ip}->{$dec_mac}->{ch}=$client_status{$dec_mac}->{ch};
+        $ip_status{$ip}->{$dec_mac}->{rx}=$client_status{$dec_mac}->{rx};
+        $ip_status{$ip}->{$dec_mac}->{tx}=$client_status{$dec_mac}->{tx};
+        $ip_status{$ip}->{$dec_mac}->{band}=$client_status{$dec_mac}->{band};
+        $ip_status{$ip}->{$dec_mac}->{uptime}=$client_status{$dec_mac}->{uptime};
+        }
+    foreach my $ip (sort {$a <=> $b} keys %ip_status) {
+        next if ($filter and $ip ne $filter);
+        $result.=expand_status($ip_status{$ip});
+        }
+    }
+
+return $result;
+}
+
+1;

+ 61 - 0
docs/wiki/update_auth_wiki.pl

@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+
+#
+# Copyright (C) Roman Dmitiriev, rnd@rajven.ru
+#
+
+use FindBin '$Bin';
+use lib "$Bin/";
+use Data::Dumper;
+use Rstat::config;
+use Rstat::main;
+use Rstat::mysql;
+use Rstat::net_utils;
+use strict;
+use warnings;
+use File::Find;
+use File::Basename;
+
+if (!$config_ref{wiki_path}) { exit; }
+
+my %content;
+find( \&wanted, $config_ref{wiki_path});
+
+foreach my $fname (keys %content) {
+
+open (FF,"<$content{$fname}") or die "unable to open file $content{$fname}!" ;
+my @tmp=<FF>;
+close(FF);
+chomp(@tmp);
+
+my $ip;
+
+foreach my $row (@tmp) {
+if ($row=~/\%META\:FIELD\{name\=\"DeviceIP\"/) {
+    if ($row=~/value\=\"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\"/) { $ip = $1; }
+    }
+}
+
+if (!$ip) { next; }
+my $auth  = get_record_sql($dbh,"SELECT * FROM User_auth WHERE deleted=0 and ip='".$ip."'");
+if (!$auth) { next; }
+print "Update id: $auth->{id} $ip => $fname\n";
+my $auth_rec;
+$auth->{WikiName}=$fname;
+update_record($dbh,'User_auth',$auth,'id='.$auth->{id});
+}
+
+print "Done!\n";
+exit;
+
+sub wanted {
+my $filename = $File::Find::name;
+my $dev_name = basename($filename);
+if ($filename =~/\.txt$/ and $filename=~/Device/) {
+    $dev_name=~s/\.txt$//;
+    $content{$dev_name}=$filename;
+    }
+return;
+}
+
+exit;

+ 85 - 0
docs/wiki/update_wiki.pl

@@ -0,0 +1,85 @@
+#!/usr/bin/perl
+
+#
+# Copyright (C) Roman Dmitiriev, rnd@rajven.ru
+#
+
+use FindBin '$Bin';
+use lib "$Bin/";
+use Data::Dumper;
+use Rstat::config;
+use Rstat::main;
+use Rstat::mysql;
+use Rstat::net_utils;
+use strict;
+use warnings;
+use File::Find;
+use File::Basename;
+
+if (!$config_ref{wiki_path}) { exit; }
+
+my %content;
+find( \&wanted, $config_ref{wiki_path});
+
+foreach my $fname (keys %content) {
+open (FF,"<$content{$fname}") or die "unable to open file $content{$fname}!" ;
+my @tmp=<FF>;
+close(FF);
+chomp(@tmp);
+
+my @wiki_dev=();
+my $ip;
+
+foreach my $row (@tmp) {
+if ($row=~/\%META\:FIELD\{name\=\"Description\"/) { next; }
+if ($row=~/\%META\:FIELD\{name\=\"Parent\"/) { next; }
+if ($row=~/\%META\:FIELD\{name\=\"ParentPort\"/) { next; }
+if ($row=~/\%META\:FIELD\{name\=\"DeviceIP\"/) {
+    if ($row=~/value\=\"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\"/) { $ip = $1; }
+    }
+if ($row=~/\%META\:FIELD\{name\=\"Mac\"/) { next; }
+push(@wiki_dev,$row);
+}
+
+if (!$ip) { next; }
+my $auth  = get_record_sql($dbh,"SELECT * FROM User_auth WHERE deleted=0 and ip='".$ip."'");
+if (!$auth) { next; }
+
+my $dSQL = "SELECT D.ip, D.building_id, D.user_id ,DP.port FROM devices AS D, device_ports AS DP, connections AS C WHERE D.deleted=0 and D.id = DP.device_id AND DP.id = C.port_id AND C.auth_id=".$auth->{id};
+my $device = get_record_sql($dbh,$dSQL);
+if (!$device or !$device->{user_id}) { next; }
+$dSQL = "SELECT * FROM User_auth WHERE WikiName IS NOT NULL AND user_id=".$device->{user_id}." AND deleted=0 AND ip='".$device->{ip}."'";
+my $device_auth = get_record_sql($dbh,$dSQL);
+if (!$device_auth) { next; }
+my $device_name = $device_auth->{WikiName};
+my $device_port = $device->{port};
+
+if ($auth->{comments}) { push(@wiki_dev,'%META:FIELD{name="Description" title="Description" value="'.$auth->{comments}.'"}%'); }
+push(@wiki_dev,'%META:FIELD{name="Parent" title="Parent" value="'.$device_name.'"}%');
+push(@wiki_dev,'%META:FIELD{name="ParentPort" title="Parent Port" value="'.$device_port.'"}%');
+push(@wiki_dev,'%META:FIELD{name="Mac" title="Mac" value="'.$auth->{mac}.'"}%');
+
+print "Found: $auth->{ip} $auth->{mac} $device_name $device_port \n";
+
+open (LG,">$content{$fname}") || die("Error open file $content{$fname}!!! die...");
+foreach my $row (@wiki_dev) {
+next if (!$row);
+print LG $row."\n";
+}
+close (LG);
+}
+
+print "Done!\n";
+exit;
+
+sub wanted {
+my $filename = $File::Find::name;
+my $dev_name = basename($filename);
+if ($filename =~/\.txt$/ and $filename=~/Device/) {
+    $dev_name=~s/\.txt$//;
+    $content{$dev_name}=$filename;
+    }
+return;
+}
+
+exit;

+ 12 - 14
html/admin/groups/index.php

@@ -9,10 +9,10 @@ if (isset($_POST["remove"])) {
             $new['ou_id'] = 0;
             $new['ou_id'] = 0;
             update_record($db_link, "User_list", "ou_id=" . $val, $new);
             update_record($db_link, "User_list", "ou_id=" . $val, $new);
             delete_record($db_link, "OU", "id=" . $val);
             delete_record($db_link, "OU", "id=" . $val);
+            }
         }
         }
-    }
     header("Location: " . $_SERVER["REQUEST_URI"]);
     header("Location: " . $_SERVER["REQUEST_URI"]);
-}
+    }
 
 
 if (isset($_POST['save'])) {
 if (isset($_POST['save'])) {
     $len = is_array($_POST['id']) ? count($_POST['id']) : 0;
     $len = is_array($_POST['id']) ? count($_POST['id']) : 0;
@@ -23,27 +23,23 @@ if (isset($_POST['save'])) {
         }
         }
         $len_all = is_array($_POST['id']) ? count($_POST['id']) : 0;
         $len_all = is_array($_POST['id']) ? count($_POST['id']) : 0;
         for ($j = 0; $j < $len_all; $j ++) {
         for ($j = 0; $j < $len_all; $j ++) {
-            if (intval($_POST['id'][$j]) != $save_id) {
-                continue;
-            }
-            $value = $_POST['f_group_name'][$j];
-            if (isset($value)) {
-                $new['ou_name'] = $value;
-                update_record($db_link, "OU", "id='{$save_id}'", $new);
+            if (intval($_POST['id'][$j]) != $save_id) { continue; }
+            $new['ou_name'] = $_POST['f_group_name'][$j];
+            $new['nagios_dir'] = $_POST['f_nagios'][$j];
+            update_record($db_link, "OU", "id='{$save_id}'", $new);
             }
             }
         }
         }
-    }
     header("Location: " . $_SERVER["REQUEST_URI"]);
     header("Location: " . $_SERVER["REQUEST_URI"]);
-}
+    }
 
 
 if (isset($_POST["create"])) {
 if (isset($_POST["create"])) {
     $ou_name = $_POST["new_ou"];
     $ou_name = $_POST["new_ou"];
     if (isset($ou_name)) {
     if (isset($ou_name)) {
         $new['ou_name'] = $ou_name;
         $new['ou_name'] = $ou_name;
         insert_record($db_link, "OU", $new);
         insert_record($db_link, "OU", $new);
-    }
+        }
     header("Location: " . $_SERVER["REQUEST_URI"]);
     header("Location: " . $_SERVER["REQUEST_URI"]);
-}
+    }
 
 
 unset($_POST);
 unset($_POST);
 require_once ($_SERVER['DOCUMENT_ROOT']."/inc/header.php");
 require_once ($_SERVER['DOCUMENT_ROOT']."/inc/header.php");
@@ -58,6 +54,7 @@ require_once ($_SERVER['DOCUMENT_ROOT']."/inc/header.php");
 <td><input type="checkbox" onClick="checkAll(this.checked);"></td>
 <td><input type="checkbox" onClick="checkAll(this.checked);"></td>
 <td><b>Id</b></td>
 <td><b>Id</b></td>
 <td><b>Название</b></td>
 <td><b>Название</b></td>
+<td><b>Nagios directory</b></td>
 <td><input type="submit" name="remove" value="Удалить"></td>
 <td><input type="submit" name="remove" value="Удалить"></td>
 </tr>
 </tr>
 <?
 <?
@@ -67,6 +64,7 @@ foreach ($t_ou as $row) {
     print "<td class=\"data\" style='padding:0'><input type=checkbox name=f_id[] value='{$row['id']}'></td>\n";
     print "<td class=\"data\" style='padding:0'><input type=checkbox name=f_id[] value='{$row['id']}'></td>\n";
     print "<td class=\"data\"><input type=\"hidden\" name='id[]' value='{$row['id']}'>{$row['id']}</td>\n";
     print "<td class=\"data\"><input type=\"hidden\" name='id[]' value='{$row['id']}'>{$row['id']}</td>\n";
     print "<td class=\"data\"><input type=\"text\" name='f_group_name[]' value='{$row['ou_name']}'></td>\n";
     print "<td class=\"data\"><input type=\"text\" name='f_group_name[]' value='{$row['ou_name']}'></td>\n";
+    print "<td class=\"data\"><input type=\"text\" name='f_nagios[]' value='{$row['nagios_dir']}'></td>\n";
     print "<td class=\"data\"><button name='save[]' value='{$row['id']}'>Сохранить</button></td>\n";
     print "<td class=\"data\"><button name='save[]' value='{$row['id']}'>Сохранить</button></td>\n";
     print "</tr>\n";
     print "</tr>\n";
 }
 }
@@ -82,4 +80,4 @@ foreach ($t_ou as $row) {
 </form>
 </form>
 <?php
 <?php
 require_once ($_SERVER['DOCUMENT_ROOT']."/inc/footer.php");
 require_once ($_SERVER['DOCUMENT_ROOT']."/inc/footer.php");
-?>
+?>

+ 16 - 3
html/inc/common.php

@@ -2905,11 +2905,11 @@ function get_cacti_graph($host_ip, $port_index)
 {
 {
     global $cacti_dbname;
     global $cacti_dbname;
     global $cacti_dbhost;
     global $cacti_dbhost;
-    global $cacti_url_path;
+    global $cacti_url;
     global $dbuser;
     global $dbuser;
     global $dbpass;
     global $dbpass;
 
 
-    if (! isset($cacti_url_path)) {
+    if (! isset($cacti_url)) {
         return;
         return;
     }
     }
 
 
@@ -2945,7 +2945,7 @@ function get_cacti_graph($host_ip, $port_index)
         return;
         return;
     }
     }
 
 
-    $result = $cacti_url_path . "/graph_image.php?local_graph_id=" . $graph_id;
+    $result = $cacti_url . "/graph_image.php?local_graph_id=" . $graph_id;
     return $result;
     return $result;
 }
 }
 
 
@@ -3177,6 +3177,19 @@ function init_option($db)
     if (! isset($hotspot_user_id)) {
     if (! isset($hotspot_user_id)) {
         $hotspot_user_id = $default_user_id;
         $hotspot_user_id = $default_user_id;
     }
     }
+
+    global $cacti_url;
+    $cacti_url = get_option($db, 58);
+    if (preg_match('/127.0.0.1/', $cacti_url)) { $cacti_url=NULL; }
+
+    global $nagios_url;
+    $nagios_url = get_option($db, 57).'/cgi-bin';
+    if (preg_match('/127.0.0.1/', $nagios_url)) { $nagios_url=NULL; }
+
+    global $torrus_url;
+    $torrus_url = get_option($db, 59).'/Collector?nodeid=if//HOST_IP//IF_NAME////inoutbps';
+    if (preg_match('/127.0.0.1/', $torrus_url)) { $torrus_url=NULL; }
+
 }
 }
 
 
 init_option($db_link);
 init_option($db_link);

+ 0 - 5
html/inc/config.php.sample

@@ -16,11 +16,6 @@ $dbpass="password";
 #$cacti_dbhost="cacti_host";
 #$cacti_dbhost="cacti_host";
 #$cacti_dbname="cacti";
 #$cacti_dbname="cacti";
 
 
-#$cacti_url_path = 'cacti_utl';
-#$nagios_url_path='nagios-cgi-bin';
-
 $ipcam_group_id=5;
 $ipcam_group_id=5;
 
 
-#$torrus_url='http://torrus.server.ru/Collector?nodeid=if//HOST_IP//IF_NAME////inoutbps';
-
 ?>
 ?>

+ 8 - 0
scripts/Rstat/mysql.pm

@@ -809,6 +809,14 @@ $config_ref{enable_quotes} = get_option($dbh,54);
 $config_ref{netflow_step} = get_option($dbh,55);
 $config_ref{netflow_step} = get_option($dbh,55);
 $config_ref{traffic_ipstat_history} = get_option($dbh,56);
 $config_ref{traffic_ipstat_history} = get_option($dbh,56);
 
 
+$config_ref{nagios_url} = get_option($dbh,57);
+$config_ref{cacti_url} = get_option($dbh,58);
+$config_ref{torrus_url} = get_option($dbh,59);
+$config_ref{wiki_url} = get_option($dbh,60);
+$config_ref{stat_url} = get_option($dbh,62);
+
+$config_ref{wiki_path} = get_option($dbh,61);
+
 #$save_detail = 1; id=23
 #$save_detail = 1; id=23
 $save_detail=get_option($dbh,23);
 $save_detail=get_option($dbh,23);
 #$add_unknown_user = 1; id=22
 #$add_unknown_user = 1; id=22

+ 13 - 0
updates/20210328/db-patch-mysql-config.sql

@@ -0,0 +1,13 @@
+INSERT INTO `config_options` (`id`, `option_name`, `description`, `uniq`, `type`, `default_value`, `min_value`, `max_value`) VALUES ('57', 'nagios_url', 'Адрес сайта nagios', '1', 'text', 'http://127.0.0.1/nagios', '0', '0'), ('58', 'cacti_url', 'Адрес сайта cacti', '1', 'text', 'http://127.0.0.1/cacti', '0', '0')
+INSERT INTO `config_options` (`id`, `option_name`, `description`, `uniq`, `type`, `default_value`, `min_value`, `max_value`) VALUES ('59', 'torrus_url', 'Адрес сайта Torrus', '1', 'text', 'http://127.0.0.1/torrus', '0', '0'), ('60', 'wiki_url', 'Адрес wiki', '1', 'text', 'http://127.0.0.1/wiki', '0', '0');
+INSERT INTO `config_options` (`id`, `option_name`, `description`, `uniq`, `type`, `default_value`, `min_value`, `max_value`) VALUES ('61', 'wiki_path', 'Путь к каталогу данных вики', '1', 'text', '/var/www/foswiki/data/', '0', '0'), ('62', 'stat_url', 'Адрес этого сайта', '1', 'text', 'http://127.0.0.1/stat', '0', '0');
+ALTER TABLE `OU` ADD `nagios_dir` VARCHAR(255) NULL DEFAULT NULL AFTER `ou_name`;
+UPDATE `OU` SET `ou_name` = '_ВСЕ_', `nagios_dir` = '/etc/nagios/any' WHERE `OU`.`id` = 0;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/voip' WHERE `OU`.`id` = 4;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/videocam' WHERE `OU`.`id` = 5;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/printers' WHERE `OU`.`id` = 6;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/switches' WHERE `OU`.`id` = 7;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/ups' WHERE `OU`.`id` = 8;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/security' WHERE `OU`.`id` = 9;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/routers' WHERE `OU`.`id` = 10;
+UPDATE `OU` SET `nagios_dir` = '/etc/nagios/ap' WHERE `OU`.`id` = 12;