1<?php 2/* 3 +-------------------------------------------------------------------------+ 4 | Copyright (C) 2004-2021 The Cacti Group | 5 | | 6 | This program is free software; you can redistribute it and/or | 7 | modify it under the terms of the GNU General Public License | 8 | as published by the Free Software Foundation; either version 2 | 9 | of the License, or (at your option) any later version. | 10 | | 11 | This program is distributed in the hope that it will be useful, | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | GNU General Public License for more details. | 15 +-------------------------------------------------------------------------+ 16 | Cacti: The Complete RRDtool-based Graphing Solution | 17 +-------------------------------------------------------------------------+ 18 | This code is designed, written, and maintained by the Cacti Group. See | 19 | about.php and/or the AUTHORS file for specific developer information. | 20 +-------------------------------------------------------------------------+ 21 | http://www.cacti.net/ | 22 +-------------------------------------------------------------------------+ 23*/ 24 25require('./include/auth.php'); 26require_once($config['base_path'] . '/lib/poller.php'); 27 28/* performing a full sync can take a lot of memory and time */ 29ini_set('memory_limit', '-1'); 30ini_set('max_execution_time', '900'); 31 32$poller_actions = array( 33 1 => __('Delete'), 34 2 => __('Disable'), 35 3 => __('Enable'), 36 5 => __('Clear Statistics'), 37); 38 39if ($config['poller_id'] == 1) { 40 $poller_actions += array(4 =>__('Full Sync')); 41} 42 43$poller_status = array( 44 0 => '<div class="deviceUnknown">' . __('New/Idle') . '</div>', 45 1 => '<div class="deviceUp">' . __('Running') . '</div>', 46 2 => '<div class="deviceRecovering">' . __('Idle') . '</div>', 47 3 => '<div class="deviceDown">' . __('Down') . '</div>', 48 4 => '<div class="deviceDisabled">' . __('Disabled') . '</div>', 49 5 => '<div class="deviceDown">' . __('Recovering') . '</div>', 50 6 => '<div class="deviceDown">' . __('Heartbeat') . '</div>', 51); 52 53/* file: pollers.php, action: edit */ 54$fields_poller_edit = array( 55 'spacer0' => array( 56 'method' => 'spacer', 57 'friendly_name' => __('Data Collector Information'), 58 ), 59 'name' => array( 60 'method' => 'textbox', 61 'friendly_name' => __('Name'), 62 'description' => __('The primary name for this Data Collector.'), 63 'value' => '|arg1:name|', 64 'size' => '50', 65 'default' => __('New Data Collector'), 66 'max_length' => '100' 67 ), 68 'hostname' => array( 69 'method' => 'textbox', 70 'friendly_name' => __('Data Collector Hostname'), 71 'description' => __('The hostname for Data Collector. It may have to be a Fully Qualified Domain name for the remote Pollers to contact it for activities such as re-indexing, Real-time graphing, etc.'), 72 'value' => '|arg1:hostname|', 73 'size' => '50', 74 'default' => '', 75 'max_length' => '100' 76 ), 77 'timezone' => array( 78 'method' => 'drop_callback', 79 'friendly_name' => __('TimeZone'), 80 'description' => __('The TimeZone for the Data Collector.'), 81 'sql' => 'SELECT Name AS id, Name AS name FROM mysql.time_zone_name ORDER BY name', 82 'action' => 'ajax_tz', 83 'id' => '|arg1:timezone|', 84 'value' => '|arg1:timezone|' 85 ), 86 'notes' => array( 87 'method' => 'textarea', 88 'friendly_name' => __('Notes'), 89 'description' => __('Notes for this Data Collectors Database.'), 90 'value' => '|arg1:notes|', 91 'textarea_rows' => 4, 92 'textarea_cols' => 50 93 ), 94 'spacer_collection' => array( 95 'method' => 'spacer', 96 'friendly_name' => __('Collection Settings'), 97 ), 98 'processes' => array( 99 'method' => 'textbox', 100 'friendly_name' => __('Processes'), 101 'description' => __('The number of Data Collector processes to use to spawn.'), 102 'value' => '|arg1:processes|', 103 'size' => '10', 104 'default' => read_config_option('concurrent_processes'), 105 'max_length' => '4' 106 ), 107 'threads' => array( 108 'method' => 'textbox', 109 'friendly_name' => __('Threads'), 110 'description' => __('The number of Spine Threads to use per Data Collector process.'), 111 'value' => '|arg1:threads|', 112 'size' => '10', 113 'default' => read_config_option('max_threads'), 114 'max_length' => '4' 115 ), 116 'sync_interval' => array( 117 'method' => 'drop_array', 118 'friendly_name' => __('Sync Interval'), 119 'description' => __('The polling sync interval in use. This setting will affect how often this poller is checked and updated.'), 120 'value' => '|arg1:sync_interval|', 121 'default' => read_config_option('poller_sync_interval'), 122 'array' => $poller_sync_intervals, 123 ), 124 'spacer_remotedb' => array( 125 'method' => 'spacer', 126 'friendly_name' => __('Remote Database Connection'), 127 ), 128 'dbhost' => array( 129 'method' => 'textbox', 130 'friendly_name' => __('Hostname'), 131 'description' => __('The hostname for the remote database server.'), 132 'value' => '|arg1:dbhost|', 133 'size' => '50', 134 'default' => '', 135 'max_length' => '100' 136 ), 137 'dbdefault' => array( 138 'method' => 'textbox', 139 'friendly_name' => __('Remote Database Name'), 140 'description' => __('The name of the remote database.'), 141 'value' => '|arg1:dbdefault|', 142 'size' => '20', 143 'default' => $database_default, 144 'max_length' => '20' 145 ), 146 'dbuser' => array( 147 'method' => 'textbox', 148 'friendly_name' => __('Remote Database User'), 149 'description' => __('The user name to use to connect to the remote database.'), 150 'value' => '|arg1:dbuser|', 151 'size' => '20', 152 'default' => $database_username, 153 'max_length' => '20' 154 ), 155 'dbpass' => array( 156 'method' => 'textbox_password', 157 'friendly_name' => __('Remote Database Password'), 158 'description' => __('The user password to use to connect to the remote database.'), 159 'value' => '|arg1:dbpass|', 160 'size' => '40', 161 'default' => $database_password, 162 'max_length' => '64' 163 ), 164 'dbport' => array( 165 'method' => 'textbox', 166 'friendly_name' => __('Remote Database Port'), 167 'description' => __('The TCP port to use to connect to the remote database.'), 168 'value' => '|arg1:dbport|', 169 'size' => '5', 170 'default' => $database_port, 171 'max_length' => '5' 172 ), 173 'dbretries' => array( 174 'method' => 'textbox', 175 'friendly_name' => __('Remote Database Retries'), 176 'description' => __('The number of times to attempt to retry to connect to the remote database.'), 177 'value' => '|arg1:dbretries|', 178 'size' => '5', 179 'default' => $database_retries, 180 'max_length' => '5' 181 ), 182 'dbssl' => array( 183 'method' => 'checkbox', 184 'friendly_name' => __('Remote Database SSL'), 185 'description' => __('If the remote database uses SSL to connect, check the checkbox below.'), 186 'value' => '|arg1:dbssl|', 187 'default' => $database_ssl ? 'on':'' 188 ), 189 'dbsslkey' => array( 190 'method' => 'textbox', 191 'friendly_name' => __('Remote Database SSL Key'), 192 'description' => __('The file holding the SSL Key to use to connect to the remote database.'), 193 'value' => '|arg1:dbsslkey|', 194 'size' => '50', 195 'default' => $database_ssl_key, 196 'max_length' => '255' 197 ), 198 'dbsslcert' => array( 199 'method' => 'textbox', 200 'friendly_name' => __('Remote Database SSL Certificate'), 201 'description' => __('The file holding the SSL Certificate to use to connect to the remote database.'), 202 'value' => '|arg1:dbsslcert|', 203 'size' => '50', 204 'default' => $database_ssl_cert, 205 'max_length' => '255' 206 ), 207 'dbsslca' => array( 208 'method' => 'textbox', 209 'friendly_name' => __('Remote Database SSL Authority'), 210 'description' => __('The file holding the SSL Certificate Authority to use to connect to the remote database. This is an optional parameter that can be required by the database provider if they have started SSL using the --ssl-mode=VERIFY_CA option.'), 211 'value' => '|arg1:dbsslca|', 212 'size' => '50', 213 'default' => $database_ssl_ca, 214 'max_length' => '255' 215 ), 216 'id' => array( 217 'method' => 'hidden', 218 'value' => '|arg1:id|', 219 ), 220 'save_component_poller' => array( 221 'method' => 'hidden', 222 'value' => '1' 223 ) 224); 225 226/* set default action */ 227set_default_action(); 228 229switch (get_request_var('action')) { 230 case 'save': 231 form_save(); 232 233 break; 234 case 'actions': 235 form_actions(); 236 237 break; 238 case 'ajax_tz': 239 print json_encode(db_fetch_assoc_prepared('SELECT Name AS label, Name AS `value` 240 FROM mysql.time_zone_name 241 WHERE Name LIKE ? 242 ORDER BY Name 243 LIMIT ' . read_config_option('autocomplete_rows'), 244 array('%' . get_nfilter_request_var('term') . '%'))); 245 246 break; 247 case 'ping': 248 test_database_connection(); 249 250 break; 251 case 'edit': 252 top_header(); 253 254 poller_edit(); 255 256 bottom_footer(); 257 break; 258 default: 259 top_header(); 260 261 pollers(); 262 263 bottom_footer(); 264 break; 265} 266 267/* -------------------------- 268 Global Form Functions 269 -------------------------- */ 270 271/* -------------------------- 272 The Save Function 273 -------------------------- */ 274 275function form_save() { 276 if (isset_request_var('save_component_poller')) { 277 278 // Common data 279 $save['id'] = get_filter_request_var('id'); 280 $save['name'] = form_input_validate(get_nfilter_request_var('name'), 'name', '', false, 3); 281 $save['hostname'] = form_input_validate(get_nfilter_request_var('hostname'), 'hostname', '', false, 3); 282 $save['timezone'] = form_input_validate(get_nfilter_request_var('timezone'), 'timezone', '', false, 3); 283 $save['notes'] = form_input_validate(get_nfilter_request_var('notes'), 'notes', '', true, 3); 284 285 // Process settings 286 $save['processes'] = form_input_validate(get_nfilter_request_var('processes'), 'processes', '^[0-9]+$', false, 3); 287 $save['threads'] = form_input_validate(get_nfilter_request_var('threads'), 'threads', '^[0-9]+$', false, 3); 288 289 if ($save['id'] != 1) { 290 $save['sync_interval'] = form_input_validate(get_nfilter_request_var('sync_interval'), 'sync_interval', '^[0-9]+$', false, 3); 291 292 // Database settings 293 $save['dbdefault'] = form_input_validate(get_nfilter_request_var('dbdefault'), 'dbdefault', '', true, 3); 294 $save['dbhost'] = form_input_validate(get_nfilter_request_var('dbhost'), 'dbhost', '', true, 3); 295 $save['dbuser'] = form_input_validate(get_nfilter_request_var('dbuser'), 'dbuser', '', true, 3); 296 $save['dbpass'] = form_input_validate(get_nfilter_request_var('dbpass'), 'dbpass', '', true, 3); 297 $save['dbport'] = form_input_validate(get_nfilter_request_var('dbport'), 'dbport', '^[0-9]+$', true, 3); 298 $save['dbretries'] = form_input_validate(get_nfilter_request_var('dbretries'), 'dbretries', '^[0-9]+$', true, 3); 299 $save['dbssl'] = isset_request_var('dbssl') ? 'on':''; 300 $save['dbsslkey'] = form_input_validate(get_nfilter_request_var('dbsslkey'), 'dbsslkey', '', true, 3); 301 $save['dbsslcert'] = form_input_validate(get_nfilter_request_var('dbsslcert'), 'dbsslcert', '', true, 3); 302 $save['dbsslca'] = form_input_validate(get_nfilter_request_var('dbsslca'), 'dbsslca', '', true, 3); 303 } 304 305 // Check for duplicate hostname 306 $error = false; 307 if (poller_check_duplicate_poller_id($save['id'], $save['hostname'], 'hostname')) { 308 raise_message('dupe_hostname', __esc('You have already used this hostname \'%s\'. Please enter a non-duplicate hostname.', $save['hostname']), MESSAGE_LEVEL_ERROR); 309 $error = true; 310 } 311 312 if (isset($save['dbhost'])) { 313 if (poller_check_duplicate_poller_id($save['id'], $save['dbhost'], 'dbhost')) { 314 raise_message('dupe_dbhost', __esc('You have already used this database hostname \'%s\'. Please enter a non-duplicate database hostname.', $save['hostname']), MESSAGE_LEVEL_ERROR); 315 $error = true; 316 } 317 } 318 319 if (isset($save['dbhost']) && $save['dbhost'] == 'localhost' && $save['id'] > 1) { 320 raise_message('poller_dbhost'); 321 } elseif ($save['id'] > 1 && poller_host_duplicate($save['id'], $save['dbhost'])) { 322 raise_message('poller_nodupe'); 323 } elseif (!is_error_message() && $error == false) { 324 $poller_id = sql_save($save, 'poller'); 325 326 if ($poller_id) { 327 raise_message(1); 328 } else { 329 raise_message(2); 330 } 331 } 332 333 header('Location: pollers.php?header=false&action=edit&id=' . (empty($poller_id) ? get_nfilter_request_var('id') : $poller_id)); 334 } 335} 336 337function poller_check_duplicate_poller_id($poller_id, $hostname, $column) { 338 $ip_addresses = array(); 339 $ip_hostnames = array(); 340 341 if (is_ipaddress($hostname)) { 342 $address = @gethostbyaddr($hostname); 343 344 if ($address != $hostname) { 345 $ip_hostnames[$address] = $address; 346 } else { 347 $ip_addresses[$address] = $address; 348 } 349 350 $ip_addresses[$hostname] = $hostname; 351 } elseif (strpos($hostname, '.') !== false) { 352 $addresses = @dns_get_record($hostname); 353 $ip = @gethostbyname($hostname); 354 355 if ($ip != $hostname) { 356 $ip_addresses[$ip] = $ip; 357 } 358 359 $ip_hostnames[$hostname] = $hostname; 360 361 if (cacti_sizeof($addresses)) { 362 foreach($addresses as $address) { 363 if (isset($address['target'])) { 364 $ip_hostnames[$address['host']] = $address['host']; 365 } 366 367 if (isset($address['host'])) { 368 $ip_hostnames[$address['host']] = $address['host']; 369 } 370 371 if (isset($address['ip'])) { 372 $ip_addresses[$address['ip']] = $address['ip']; 373 } 374 } 375 } 376 } else { 377 $ip_hostname[$hostname] = $hostname; 378 379 $address = @gethostbyname($hostname); 380 381 if ($address != $hostname) { 382 $ip_addresses[$address] = $address; 383 } 384 } 385 386 $sql_where1 = ''; 387 if (cacti_sizeof($ip_addresses)) { 388 $sql_where1 = "$column IN ('" . implode("','", $ip_addresses) . "')"; 389 } 390 391 $sql_where2 = ''; 392 if (cacti_sizeof($ip_hostnames)) { 393 foreach($ip_hostnames as $host) { 394 $parts = explode('.', $host); 395 $sql_where2 .= ($sql_where2 != '' ? ' OR ':' (') . 396 "($column = " . db_qstr($parts[0]) . 397 " OR $column LIKE " . db_qstr($parts[0] . '%') . 398 " OR $column = " . db_qstr($host) . ")"; 399 } 400 $sql_where2 .= ')'; 401 } 402 403 if ($sql_where1 != '' || $sql_where2 != '') { 404 $sql_where = ' AND ' . $sql_where1 . ($sql_where1 != '' && $sql_where2 != '' ? ' OR ':'') . $sql_where2; 405 } else { 406 $sql_where = ''; 407 } 408 409 $duplicate = db_fetch_cell_prepared("SELECT id 410 FROM poller 411 WHERE id != ? 412 $sql_where", 413 array($poller_id)); 414 415 if (empty($duplicate)) { 416 return false; 417 } else { 418 return true; 419 } 420} 421 422function poller_host_duplicate($poller_id, $host) { 423 if ($host == 'localhost') { 424 return true; 425 } else { 426 return db_fetch_cell_prepared('SELECT COUNT(*) 427 FROM poller 428 WHERE dbhost LIKE "' . $host . '%" 429 AND id != ?', 430 array($poller_id)); 431 } 432} 433 434function form_actions() { 435 global $config, $poller_actions; 436 437 /* ================= input validation ================= */ 438 get_filter_request_var('drp_action', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^([a-zA-Z0-9_]+)$/'))); 439 /* ==================================================== */ 440 441 /* if we are to save this form, instead of display it */ 442 if (isset_request_var('selected_items')) { 443 $selected_items = sanitize_unserialize_selected_items(get_nfilter_request_var('selected_items')); 444 445 if ($selected_items != false) { 446 if (get_nfilter_request_var('drp_action') == '1') { // delete 447 db_execute('DELETE FROM poller WHERE ' . array_to_sql_or($selected_items, 'id')); 448 db_execute('UPDATE host SET poller_id=1 WHERE deleted="" AND ' . array_to_sql_or($selected_items, 'poller_id')); 449 db_execute('UPDATE automation_networks SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 450 db_execute('UPDATE automation_processes SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 451 db_execute('UPDATE poller_command SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 452 db_execute('UPDATE poller_item SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 453 db_execute('UPDATE poller_output_realtime SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 454 db_execute('UPDATE poller_time SET poller_id=1 WHERE ' . array_to_sql_or($selected_items, 'poller_id')); 455 456 cacti_log('NOTE: The poller(s) with the id(s): ' . implode(',', $selected_items) . ' deleted by user ' . $_SESSION['sess_user_id'], false, 'WEBUI'); 457 } elseif (get_request_var('drp_action') == '2') { // disable 458 db_execute('UPDATE poller SET disabled="on" WHERE ' . array_to_sql_or($selected_items, 'id')); 459 460 cacti_log('NOTE: The poller(s) with the id(s): ' . implode(',', $selected_items) . ' disabled by user ' . $_SESSION['sess_user_id'], false, 'WEBUI'); 461 } elseif (get_request_var('drp_action') == '3') { // enable 462 db_execute('UPDATE poller SET disabled="" WHERE ' . array_to_sql_or($selected_items, 'id')); 463 464 cacti_log('NOTE: The poller(s) with the id(s): ' . implode(',', $selected_items) . ' enabled by user ' . $_SESSION['sess_user_id'], false, 'WEBUI'); 465 } elseif (get_request_var('drp_action') == '4') { // full sync 466 cacti_session_close(); 467 468 $success = array(); 469 $failed = array(); 470 $ids = array(); 471 472 foreach($selected_items as $item) { 473 // Operation not allowed on the main poller 474 if ($item == 1) { 475 continue; 476 } 477 478 $ids[] = $item; 479 480 $poller = db_fetch_row_prepared('SELECT * 481 FROM poller 482 WHERE id = ?', 483 array($item)); 484 485 if ($poller['dbhost'] == 'localhost') { 486 raise_message('poller_dbhost'); 487 continue; 488 } elseif ($item == 1) { 489 raise_message('poller_nomain'); 490 continue; 491 } else { 492 if (replicate_out($item)) { 493 $success[] = $item; 494 495 db_execute_prepared('UPDATE poller 496 SET last_sync = NOW() 497 WHERE id = ?', 498 array($item)); 499 } else { 500 $failed[] = $item; 501 } 502 } 503 } 504 505 cacti_session_start(); 506 507 if (cacti_sizeof($failed)) { 508 cacti_log('WARNING: Some selected Remote Data Collectors in [' . implode(', ', $ids) . '] failed synchronization by user ' . get_username($_SESSION['sess_user_id']) . ', Successful/Failed[' . cacti_sizeof($success) . '/' . cacti_sizeof($failed) . ']. See log for details.', false, 'WEBUI'); 509 } else { 510 cacti_log('NOTE: All selected Remote Data Collectors in [' . implode(', ', $ids) . '] synchronized correctly by user ' . get_username($_SESSION['sess_user_id']), false, 'WEBUI'); 511 } 512 } elseif (get_request_var('drp_action') == '5') { // clear statistics 513 foreach($selected_items as $item) { 514 db_execute_prepared('UPDATE poller 515 SET total_time = 0, max_time = 0, min_time = 9999999, avg_time = 0, total_polls = 0 516 WHERE id = ?', 517 array($item)); 518 } 519 520 raise_message('poller_clear', __('Data Collector Statistics cleared.'), MESSAGE_LEVEL_INFO); 521 } 522 } 523 524 header('Location: pollers.php?header=false'); 525 exit; 526 } 527 528 /* setup some variables */ 529 $pollers = ''; $i = 0; 530 531 /* loop through each of the graphs selected on the previous page and get more info about them */ 532 foreach ($_POST as $var => $val) { 533 if (preg_match('/^chk_([0-9]+)$/', $var, $matches)) { 534 /* ================= input validation ================= */ 535 input_validate_input_number($matches[1]); 536 /* ==================================================== */ 537 538 $pollers .= '<li>' . html_escape(db_fetch_cell_prepared('SELECT name FROM poller WHERE id = ?', array($matches[1]))) . '</li>'; 539 $poller_array[$i] = $matches[1]; 540 541 $i++; 542 } 543 } 544 545 top_header(); 546 547 form_start('pollers.php'); 548 549 html_start_box($poller_actions[get_nfilter_request_var('drp_action')], '60%', '', '3', 'center', ''); 550 551 if (isset($poller_array) && cacti_sizeof($poller_array)) { 552 if (get_nfilter_request_var('drp_action') == '1') { // delete 553 print "<tr> 554 <td class='textArea' class='odd'> 555 <p>" . __n('Click \'Continue\' to delete the following Data Collector. Note, all devices will be disassociated from this Data Collector and mapped back to the Main Cacti Data Collector.', 'Click \'Continue\' to delete all following Data Collectors. Note, all devices will be disassociated from these Data Collectors and mapped back to the Main Cacti Data Collector.', cacti_sizeof($poller_array)) . "</p> 556 <div class='itemlist'><ul>$pollers</ul></div> 557 </td> 558 </tr>\n"; 559 560 $save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'> <input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Delete Data Collector', 'Delete Data Collectors', cacti_sizeof($poller_array)) . "'>"; 561 } elseif (get_request_var('drp_action') == '2') { // disable 562 print "<tr> 563 <td class='textArea' class='odd'> 564 <p>" . __n('Click \'Continue\' to disable the following Data Collector.', 'Click \'Continue\' to disable the following Data Collectors.', cacti_sizeof($poller_array)) . "</p> 565 <div class='itemlist'><ul>$pollers</ul></div> 566 </td> 567 </tr>\n"; 568 569 $save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'> <input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Disable Data Collector', 'Disable Data Collectors', cacti_sizeof($poller_array)) . "'>"; 570 } elseif (get_request_var('drp_action') == '3') { // enable 571 print "<tr> 572 <td class='textArea' class='odd'> 573 <p>" . __n('Click \'Continue\' to enable the following Data Collector.', 'Click \'Continue\' to enable the following Data Collectors.', cacti_sizeof($poller_array)) . "</p> 574 <div class='itemlist'><ul>$pollers</ul></div> 575 </td> 576 </tr>\n"; 577 578 $save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'> <input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Enable Data Collector', 'Enable Data Collectors', cacti_sizeof($poller_array)) . "'>"; 579 } elseif (get_request_var('drp_action') == '4') { // full sync 580 print "<tr> 581 <td class='textArea' class='odd'> 582 <p>" . __n('Click \'Continue\' to Synchronize the Remote Data Collector for Offline Operation.', 'Click \'Continue\' to Synchronize the Remote Data Collectors for Offline Operation.', cacti_sizeof($poller_array)) . "</p> 583 <div class='itemlist'><ul>$pollers</ul></div> 584 </td> 585 </tr>\n"; 586 587 $save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'> <input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Enable Data Collector', 'Synchronize Remote Data Collectors', cacti_sizeof($poller_array)) . "'>"; 588 } elseif (get_request_var('drp_action') == '5') { // clear statistics 589 print "<tr> 590 <td class='textArea' class='odd'> 591 <p>" . __n('Click \'Continue\' to Clear Data Collector Statistics for the Data Collector.', 'Click \'Continue\' to Clear DAta Collector Statistics for the Data Collectors.', cacti_sizeof($poller_array)) . "</p> 592 <div class='itemlist'><ul>$pollers</ul></div> 593 </td> 594 </tr>\n"; 595 596 $save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'> <input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Clear Statistics for Data Collector', 'Clear Statistics for Data Collectors', cacti_sizeof($poller_array)) . "'>"; 597 } 598 } else { 599 raise_message(40); 600 header('Location: pollers.php?header=false'); 601 exit; 602 } 603 604 print "<tr> 605 <td class='saveRow'> 606 <input type='hidden' name='action' value='actions'> 607 <input type='hidden' name='selected_items' value='" . (isset($poller_array) ? serialize($poller_array) : '') . "'> 608 <input type='hidden' name='drp_action' value='" . html_escape(get_nfilter_request_var('drp_action')) . "'> 609 $save_html 610 </td> 611 </tr>\n"; 612 613 html_end_box(); 614 615 form_end(); 616 617 bottom_footer(); 618} 619 620/* --------------------- 621 Site Functions 622 --------------------- */ 623 624function poller_edit() { 625 global $fields_poller_edit; 626 627 /* ================= input validation ================= */ 628 get_filter_request_var('id'); 629 /* ==================================================== */ 630 631 if (!isempty_request_var('id')) { 632 $poller = db_fetch_row_prepared('SELECT * 633 FROM poller 634 WHERE id = ?', 635 array(get_request_var('id'))); 636 637 $header_label = __esc('Site [edit: %s]', $poller['name']); 638 } else { 639 $poller = array(); 640 641 $header_label = __('Site [new]'); 642 } 643 644 form_start('pollers.php', 'poller'); 645 646 html_start_box($header_label, '100%', true, '3', 'center', ''); 647 648 if (cacti_sizeof($poller)) { 649 if ($poller['id'] == 1) { 650 unset($fields_poller_edit['sync_interval']); 651 unset($fields_poller_edit['spacer_remotedb']); 652 unset($fields_poller_edit['dbdefault']); 653 unset($fields_poller_edit['dbhost']); 654 unset($fields_poller_edit['dbuser']); 655 unset($fields_poller_edit['dbpass']); 656 unset($fields_poller_edit['dbport']); 657 unset($fields_poller_edit['dbretries']); 658 unset($fields_poller_edit['dbssl']); 659 unset($fields_poller_edit['dbsslkey']); 660 unset($fields_poller_edit['dbsslcert']); 661 unset($fields_poller_edit['dbsslca']); 662 } 663 664 if ($poller['timezone'] == '') { 665 $poller['timezone'] = ini_get('date.timezone'); 666 } 667 } 668 669 draw_edit_form( 670 array( 671 'config' => array('no_form_tag' => true), 672 'fields' => inject_form_variables($fields_poller_edit, (isset($poller) ? $poller : array())) 673 ) 674 ); 675 676 $tip_text = __('Remote Data Collectors must be able to communicate to the Main Data Collector, and vice versa. Use this button to verify that the Main Data Collector can communicate to this Remote Data Collector.'); 677 678 if (read_config_option('hide_form_description') == 'on') { 679 $tooltip = '<br><span class="formFieldDescription">' . $tip_text . '</span>'; 680 } else { 681 $tooltip = '<div class="formTooltip">' . str_replace("\n", '', display_tooltip($tip_text)) . '</div>'; 682 } 683 684 $row_html = '<div class="formRow odd"><div class="formColumnLeft"><div class="formFieldName">' . __('Test Database Connection') . $tooltip . '</div></div><div class="formColumnRight"><input type="button" class="ui-button ui-corner-all ui-widget" id="dbtest" value="' . __esc('Test Connection') . '"><span id="results"></span></div></div>'; 685 686 $pt = read_config_option('poller_type'); 687 688 if (isset($poller) && cacti_sizeof($poller)) { 689 if ($poller['id'] > 1) { 690 ?> 691 <script type='text/javascript'> 692 pt = <?php print $pt;?>; 693 694 function showHideRemoteDB() { 695 var hasSSL = $('#dbssl').is(':checked'); 696 if (hasSSL) { 697 $('#row_dbsslkey').show(); 698 $('#row_dbsslcert').show(); 699 $('#row_dbsslca').show(); 700 } else { 701 $('#row_dbsslkey').hide(); 702 $('#row_dbsslcert').hide(); 703 $('#row_dbsslca').hide(); 704 } 705 } 706 707 $(function() { 708 $('#row_dbsslca').after('<?php print $row_html;?>'); 709 $('#dbssl').click(function() { 710 showHideRemoteDB(); 711 }); 712 713 $('#dbtest').click(function() { 714 ping_database(); 715 }); 716 717 showHideRemoteDB(); 718 719 if (pt == 1) { 720 $('#row_threads').hide(); 721 } 722 }); 723 724 function ping_database() { 725 dbssl = $('#dbssl').is(':checked') ? 'on':''; 726 727 $.post('pollers.php', { 728 __csrf_magic: csrfMagicToken, 729 action: 'ping', 730 dbdefault: $('#dbdefault').val(), 731 dbhost: $('#dbhost').val(), 732 dbuser: $('#dbuser').val(), 733 dbpass: $('#dbpass').val(), 734 dbport: $('#dbport').val(), 735 dbretries: $('#dbretries').val(), 736 dbssl: dbssl, 737 dbsslkey: $('#dbsslkey').val(), 738 dbsslcert: $('#dbsslcert').val(), 739 dbsslca: $('#dbsslca').val() 740 }).done(function(data) { 741 $('#results').empty().show().html(data).fadeOut(2000); 742 }); 743 } 744 </script> 745 <?php 746 } else { 747 ?> 748 <script type='text/javascript'> 749 pt = <?php print $pt;?>; 750 751 $(function() { 752 if (pt == 1) { 753 $('#row_threads').hide(); 754 } 755 }); 756 </script> 757 <?php 758 } 759 } 760 761 html_end_box(true, true); 762 763 form_save_button('pollers.php', 'return'); 764} 765 766function test_database_connection($poller = array()) { 767 if (!cacti_sizeof($poller)) { 768 $poller['dbtype'] = 'mysql'; 769 770 $fields = array( 771 'dbhost', 772 'dbuser', 773 'dbpass', 774 'dbdefault', 775 'dbport', 776 'dbretries', 777 'dbssl', 778 'dbsslkey', 779 'dbsslcert', 780 'dbsslca' 781 ); 782 783 foreach ($fields as $field) { 784 if ($field == 'dbssl') { 785 if (isset_request_var('dbssl') && get_nfilter_request_var('dbssl') == 'on') { 786 $poller['dbssl'] = 'on'; 787 } else { 788 $poller['dbssl'] = ''; 789 } 790 } elseif (isset_request_var($field)) { 791 $poller[$field] = get_nfilter_request_var($field); 792 } else { 793 print 'ERROR: DB Connection Column ' . $field . ' Missing'; 794 return false; 795 } 796 } 797 } 798 799 $connection = db_connect_real( 800 $poller['dbhost'], 801 $poller['dbuser'], 802 $poller['dbpass'], 803 $poller['dbdefault'], 804 $poller['dbtype'], 805 $poller['dbport'], 806 $poller['dbretries'], 807 $poller['dbssl'], 808 $poller['dbsslkey'], 809 $poller['dbsslcert'], 810 $poller['dbsslca'] 811 ); 812 813 if (is_object($connection)) { 814 db_close($connection); 815 print __('Connection Successful'); 816 } else { 817 print __('Connection Failed'); 818 } 819} 820 821function pollers() { 822 global $poller_actions, $poller_status, $item_rows; 823 824 /* ================= input validation and session storage ================= */ 825 $filters = array( 826 'rows' => array( 827 'filter' => FILTER_VALIDATE_INT, 828 'pageset' => true, 829 'default' => '-1' 830 ), 831 'page' => array( 832 'filter' => FILTER_VALIDATE_INT, 833 'default' => '1' 834 ), 835 'refresh' => array( 836 'filter' => FILTER_VALIDATE_INT, 837 'default' => '20' 838 ), 839 'filter' => array( 840 'filter' => FILTER_DEFAULT, 841 'pageset' => true, 842 'default' => '' 843 ), 844 'sort_column' => array( 845 'filter' => FILTER_CALLBACK, 846 'default' => 'name', 847 'options' => array('options' => 'sanitize_search_string') 848 ), 849 'sort_direction' => array( 850 'filter' => FILTER_CALLBACK, 851 'default' => 'ASC', 852 'options' => array('options' => 'sanitize_search_string') 853 ) 854 ); 855 856 validate_store_request_vars($filters, 'sess_pollers'); 857 /* ================= input validation ================= */ 858 859 $refresh['page'] = 'pollers.php?header=false'; 860 $refresh['seconds'] = get_request_var('refresh'); 861 $refresh['logout'] = 'false'; 862 863 set_page_refresh($refresh); 864 865 if (get_request_var('rows') == '-1') { 866 $rows = read_config_option('num_rows_table'); 867 } else { 868 $rows = get_request_var('rows'); 869 } 870 871 html_start_box( __('Data Collectors'), '100%', '', '3', 'center', ''); 872 873 ?> 874 <tr class='even'> 875 <td> 876 <form id='form_poller' action='pollers.php'> 877 <table class='filterTable'> 878 <tr> 879 <td> 880 <?php print __('Search');?> 881 </td> 882 <td> 883 <input type='text' class='ui-state-default ui-corner-all' id='filter' size='25' value='<?php print html_escape_request_var('filter');?>'> 884 </td> 885 <td> 886 <?php print __('Collectors');?> 887 </td> 888 <td> 889 <select id='rows' onChange='applyFilter()'> 890 <option value='-1'<?php print (get_request_var('rows') == '-1' ? ' selected>':'>') . __('Default');?></option> 891 <?php 892 if (cacti_sizeof($item_rows)) { 893 foreach ($item_rows as $key => $value) { 894 print "<option value='" . $key . "'"; if (get_request_var('rows') == $key) { print ' selected'; } print '>' . html_escape($value) . "</option>\n"; 895 } 896 } 897 ?> 898 </select> 899 </td> 900 <td> 901 <?php print __('Refresh');?> 902 </td> 903 <td> 904 <select id='refresh' onChange='applyFilter()'> 905 <?php 906 $frequency = array( 907 5 => __('%d Seconds', 5), 908 10 => __('%d Seconds', 10), 909 20 => __('%d Seconds', 20), 910 30 => __('%d Seconds', 30), 911 45 => __('%d Seconds', 45), 912 60 => __('%d Minute', 1), 913 120 => __('%d Minutes', 2), 914 300 => __('%d Minutes', 5) 915 ); 916 917 foreach ($frequency as $r => $row) { 918 echo "<option value='" . $r . "'" . (isset_request_var('refresh') && $r == get_request_var('refresh') ? ' selected' : '') . '>' . $row . '</option>'; 919 } 920 ?> 921 </select> 922 </td> 923 <td> 924 <span> 925 <input type='submit' class='ui-button ui-corner-all ui-widget' id='go' value='<?php print __esc('Go');?>' title='<?php print __esc('Set/Refresh Filters');?>'> 926 <input type='button' class='ui-button ui-corner-all ui-widget' id='clear' value='<?php print __esc('Clear');?>' title='<?php print __esc('Clear Filters');?>'> 927 </span> 928 </td> 929 </tr> 930 </table> 931 </form> 932 <script type='text/javascript'> 933 934 function applyFilter() { 935 strURL = 'pollers.php?header=false'; 936 strURL += '&filter='+$('#filter').val(); 937 strURL += '&refresh='+$('#refresh').val(); 938 strURL += '&rows='+$('#rows').val(); 939 loadPageNoHeader(strURL); 940 } 941 942 function clearFilter() { 943 strURL = 'pollers.php?clear=1&header=false'; 944 loadPageNoHeader(strURL); 945 } 946 947 $(function() { 948 $('#clear').click(function() { 949 clearFilter(); 950 }); 951 952 $('#form_poller').submit(function(event) { 953 event.preventDefault(); 954 applyFilter(); 955 }); 956 }); 957 958 </script> 959 </td> 960 </tr> 961 <?php 962 963 html_end_box(); 964 965 /* form the 'where' clause for our main sql query */ 966 if (get_request_var('filter') != '') { 967 $sql_where = 'WHERE name LIKE ' . db_qstr('%' . get_request_var('filter') . '%'); 968 } else { 969 $sql_where = ''; 970 } 971 972 $total_rows = db_fetch_cell("SELECT COUNT(*) FROM poller $sql_where"); 973 974 $sql_order = get_order_string(); 975 $sql_limit = ' LIMIT ' . ($rows*(get_request_var('page')-1)) . ',' . $rows; 976 977 $pollers = db_fetch_assoc("SELECT poller.*, UNIX_TIMESTAMP() - UNIX_TIMESTAMP(poller.last_status) as heartbeat, count(h.id) AS hosts 978 FROM poller 979 LEFT JOIN host AS h 980 ON h.poller_id=poller.id 981 $sql_where 982 GROUP BY poller.id 983 $sql_order 984 $sql_limit"); 985 986 $nav = html_nav_bar('pollers.php?filter=' . get_request_var('filter'), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 5, __('Pollers'), 'page', 'main'); 987 988 form_start('pollers.php', 'chk'); 989 990 print $nav; 991 992 html_start_box('', '100%', '', '3', 'center', ''); 993 994 $display_text = array( 995 'name' => array('display' => __('Collector Name'), 'align' => 'left', 'sort' => 'ASC', 'tip' => __('The Name of this Data Collector.')), 996 'id' => array('display' => __('ID'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The unique id associated with this Data Collector.')), 997 'hostname' => array('display' => __('Hostname'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The Hostname where the Data Collector is running.')), 998 'status' => array('display' => __('Status'), 'align' => 'center', 'sort' => 'DESC', 'tip' => __('The Status of this Data Collector.')), 999 'nosort0' => array('display' => __('Proc/Threads'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The Number of Poller Processes and Threads for this Data Collector.')), 1000 'total_time' => array('display' => __('Polling Time'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The last data collection time for this Data Collector.')), 1001 'nosort1' => array('display' => __('Avg/Max'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The Average and Maximum Collector timings for this Data Collector.')), 1002 'hosts' => array('display' => __('Devices'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The number of Devices associated with this Data Collector.')), 1003 'snmp' => array('display' => __('SNMP Gets'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The number of SNMP gets associated with this Collector.')), 1004 'script' => array('display' => __('Scripts'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The number of script calls associated with this Data Collector.')), 1005 'server' => array('display' => __('Servers'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The number of script server calls associated with this Data Collector.')), 1006 'last_update' => array('display' => __('Last Finished'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The last time this Data Collector completed.')), 1007 'last_status' => array('display' => __('Last Update'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The last time this Data Collector checked in with the main Cacti site.')), 1008 'last_sync' => array('display' => __('Last Sync'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The last time this Data Collector was full synced with main Cacti site.'))); 1009 1010 html_header_sort_checkbox($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false); 1011 1012 $i = 0; 1013 if (cacti_sizeof($pollers)) { 1014 foreach ($pollers as $poller) { 1015 if ($poller['id'] == 1) { 1016 $disabled = true; 1017 } else { 1018 $disabled = false; 1019 } 1020 1021 if ($poller['disabled'] == 'on') { 1022 $poller['status'] = 4; 1023 }else if ($poller['heartbeat'] > 310) { 1024 $poller['status'] = 6; 1025 } 1026 1027 $mma = round($poller['avg_time'], 2) . '/' . round($poller['max_time'], 2); 1028 1029 if (empty($poller['name'])) { 1030 $poller['name'] = '<no name>'; 1031 } 1032 1033 $pt = read_config_option('poller_type'); 1034 1035 form_alternate_row('line' . $poller['id'], true, $disabled); 1036 form_selectable_cell(filter_value($poller['name'], get_request_var('filter'), 'pollers.php?action=edit&id=' . $poller['id']), $poller['id']); 1037 form_selectable_cell($poller['id'], $poller['id'], '', 'right'); 1038 form_selectable_ecell($poller['hostname'], $poller['id'], '', 'right'); 1039 form_selectable_cell($poller_status[$poller['status']], $poller['id'], '', 'center'); 1040 form_selectable_cell($poller['processes'] . '/' . ($pt == 2 ? $poller['threads']:'-'), $poller['id'], '', 'right'); 1041 form_selectable_cell(number_format_i18n($poller['total_time'], 2), $poller['id'], '', 'right'); 1042 form_selectable_cell($mma, $poller['id'], '', 'right'); 1043 form_selectable_cell(number_format_i18n($poller['hosts'], '-1'), $poller['id'], '', 'right'); 1044 form_selectable_cell(number_format_i18n($poller['snmp'], '-1'), $poller['id'], '', 'right'); 1045 form_selectable_cell(number_format_i18n($poller['script'], '-1'), $poller['id'], '', 'right'); 1046 form_selectable_cell(number_format_i18n($poller['server'], '-1'), $poller['id'], '', 'right'); 1047 form_selectable_cell(substr($poller['last_update'], 5), $poller['id'], '', 'right'); 1048 form_selectable_cell(substr($poller['last_status'], 5), $poller['id'], '', 'right'); 1049 1050 if ($poller['id'] == 1) { 1051 form_selectable_cell(__('N/A'), $poller['id'], '', 'right'); 1052 } else { 1053 form_selectable_cell(substr($poller['last_sync'], 5), $poller['id'], '', 'right'); 1054 } 1055 1056 form_checkbox_cell($poller['name'], $poller['id'], $disabled); 1057 form_end_row(); 1058 } 1059 } else { 1060 print "<tr class='tableRow'><td colspan='" . (cacti_sizeof($display_text)+1) . "'><em>" . __('No Data Collectors Found') . "</em></td></tr>\n"; 1061 } 1062 1063 html_end_box(false); 1064 1065 if (cacti_sizeof($pollers)) { 1066 print $nav; 1067 } 1068 1069 /* draw the dropdown containing a list of available actions for this form */ 1070 draw_actions_dropdown($poller_actions); 1071 1072 form_end(); 1073} 1074 1075