1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (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** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22require_once dirname(__FILE__).'/graphs.inc.php'; 23require_once dirname(__FILE__).'/maps.inc.php'; 24require_once dirname(__FILE__).'/users.inc.php'; 25 26/** 27 * @param array $filter 28 * @param array $filter['groupids'] (optional) 29 * @param array $filter['exclude_groupids'] (optional) 30 * @param array $filter['hostids'] (optional) 31 * @param string $filter['problem'] (optional) 32 * @param array $filter['severities'] (optional) 33 * @param int $filter['show_suppressed'] (optional) 34 * @param int $filter['hide_empty_groups'] (optional) 35 * @param int $filter['ext_ack'] (optional) 36 * @param int $filter['show_opdata'] (optional) 37 * 38 * @return array 39 */ 40function getSystemStatusData(array $filter) { 41 $filter_groupids = (array_key_exists('groupids', $filter) && $filter['groupids']) ? $filter['groupids'] : null; 42 $filter_hostids = (array_key_exists('hostids', $filter) && $filter['hostids']) ? $filter['hostids'] : null; 43 $filter_severities = (array_key_exists('severities', $filter) && $filter['severities']) 44 ? $filter['severities'] 45 : range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1); 46 $filter_ext_ack = array_key_exists('ext_ack', $filter) 47 ? $filter['ext_ack'] 48 : EXTACK_OPTION_ALL; 49 $filter_evaltype = array_key_exists('evaltype', $filter) ? $filter['evaltype'] : TAG_EVAL_TYPE_AND_OR; 50 $filter_tags = array_key_exists('tags', $filter) ? $filter['tags'] : []; 51 $show_opdata = array_key_exists('show_opdata', $filter) && $filter['show_opdata'] != OPERATIONAL_DATA_SHOW_NONE; 52 53 if (array_key_exists('exclude_groupids', $filter) && $filter['exclude_groupids']) { 54 if ($filter_hostids === null) { 55 // Get all groups if no selected groups defined. 56 if ($filter_groupids === null) { 57 $filter_groupids = array_keys(API::HostGroup()->get([ 58 'output' => [], 59 'real_hosts' => true, 60 'preservekeys' => true 61 ])); 62 } 63 64 $filter_groupids = array_diff($filter_groupids, $filter['exclude_groupids']); 65 66 // Get available hosts. 67 $filter_hostids = array_keys(API::Host()->get([ 68 'output' => [], 69 'groupids' => $filter_groupids, 70 'preservekeys' => true 71 ])); 72 } 73 74 $exclude_hostids = array_keys(API::Host()->get([ 75 'output' => [], 76 'groupids' => $filter['exclude_groupids'], 77 'preservekeys' => true 78 ])); 79 80 $filter_hostids = array_diff($filter_hostids, $exclude_hostids); 81 } 82 83 $data = [ 84 'groups' => API::HostGroup()->get([ 85 'output' => ['groupid', 'name'], 86 'groupids' => $filter_groupids, 87 'hostids' => $filter_hostids, 88 'monitored_hosts' => true, 89 'preservekeys' => true 90 ]), 91 'triggers' => [], 92 'actions' => [], 93 'stats' => [], 94 'allowed' => [ 95 'ui_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS), 96 'add_comments' => CWebUser::checkAccess(CRoleHelper::ACTIONS_ADD_PROBLEM_COMMENTS), 97 'change_severity' => CWebUser::checkAccess(CRoleHelper::ACTIONS_CHANGE_SEVERITY), 98 'acknowledge' => CWebUser::checkAccess(CRoleHelper::ACTIONS_ACKNOWLEDGE_PROBLEMS), 99 'close' => CWebUser::checkAccess(CRoleHelper::ACTIONS_CLOSE_PROBLEMS) 100 ] 101 ]; 102 103 CArrayHelper::sort($data['groups'], [['field' => 'name', 'order' => ZBX_SORT_UP]]); 104 105 $default_stats = []; 106 107 for ($severity = TRIGGER_SEVERITY_COUNT - 1; $severity >= TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity--) { 108 if (in_array($severity, $filter_severities)) { 109 $default_stats[$severity] = ['count' => 0, 'problems' => [], 'count_unack' => 0, 'problems_unack' => []]; 110 } 111 } 112 113 $data['stats'] = $default_stats; 114 115 foreach ($data['groups'] as &$group) { 116 $group['stats'] = $default_stats; 117 $group['has_problems'] = false; 118 } 119 unset($group); 120 121 $options = [ 122 'output' => ['eventid', 'r_eventid', 'objectid', 'clock', 'ns', 'name', 'acknowledged', 'severity'], 123 'selectAcknowledges' => ['action'], 124 'groupids' => array_keys($data['groups']), 125 'hostids' => $filter_hostids, 126 'evaltype' => $filter_evaltype, 127 'tags' => $filter_tags, 128 'source' => EVENT_SOURCE_TRIGGERS, 129 'object' => EVENT_OBJECT_TRIGGER, 130 'suppressed' => false, 131 'sortfield' => ['eventid'], 132 'sortorder' => ZBX_SORT_DOWN, 133 'preservekeys' => true 134 ]; 135 136 if (array_key_exists('severities', $filter)) { 137 $filter_severities = implode(',', $filter['severities']); 138 $all_severities = implode(',', range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1)); 139 140 if ($filter_severities !== '' && $filter_severities !== $all_severities) { 141 $options['severities'] = $filter['severities']; 142 } 143 } 144 145 if (array_key_exists('show_suppressed', $filter) && $filter['show_suppressed']) { 146 unset($options['suppressed']); 147 $options['selectSuppressionData'] = ['maintenanceid', 'suppress_until']; 148 } 149 150 if ($filter_ext_ack == EXTACK_OPTION_UNACK) { 151 $options['acknowledged'] = false; 152 } 153 154 if (array_key_exists('problem', $filter) && $filter['problem'] !== '') { 155 $options['search'] = ['name' => $filter['problem']]; 156 } 157 158 $problems = API::Problem()->get($options); 159 if ($problems) { 160 $triggerids = []; 161 162 foreach ($problems as $problem) { 163 $triggerids[$problem['objectid']] = true; 164 } 165 166 $options = [ 167 'output' => ['priority', 'manual_close'], 168 'selectGroups' => ['groupid'], 169 'selectHosts' => ['name'], 170 'triggerids' => array_keys($triggerids), 171 'monitored' => true, 172 'skipDependent' => true, 173 'preservekeys' => true 174 ]; 175 176 if ($show_opdata) { 177 $options['selectFunctions'] = ['itemid']; 178 $options['output'] = array_merge($options['output'], 179 ['expression', 'recovery_mode', 'recovery_expression', 'opdata'] 180 ); 181 } 182 183 $data['triggers'] = API::Trigger()->get($options); 184 185 if ($show_opdata && $data['triggers']) { 186 $items = API::Item()->get([ 187 'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type', 'units'], 188 'selectValueMap' => ['mappings'], 189 'triggerids' => array_keys($data['triggers']), 190 'webitems' => true, 191 'preservekeys' => true 192 ]); 193 194 foreach ($data['triggers'] as &$trigger) { 195 foreach ($trigger['functions'] as $function) { 196 $trigger['items'][] = $items[$function['itemid']]; 197 } 198 unset($trigger['functions']); 199 } 200 unset($trigger); 201 } 202 203 foreach ($data['triggers'] as &$trigger) { 204 CArrayHelper::sort($trigger['hosts'], [['field' => 'name', 'order' => ZBX_SORT_UP]]); 205 } 206 unset($trigger); 207 208 foreach ($problems as $eventid => $problem) { 209 if (!array_key_exists($problem['objectid'], $data['triggers'])) { 210 unset($problems[$eventid]); 211 } 212 } 213 214 $visible_problems = []; 215 216 foreach ($problems as $eventid => $problem) { 217 $trigger = $data['triggers'][$problem['objectid']]; 218 219 $data['stats'][$problem['severity']]['count']++; 220 if ($problem['acknowledged'] == EVENT_NOT_ACKNOWLEDGED) { 221 $data['stats'][$problem['severity']]['count_unack']++; 222 } 223 224 // groups 225 foreach ($trigger['groups'] as $trigger_group) { 226 if (!array_key_exists($trigger_group['groupid'], $data['groups'])) { 227 continue; 228 } 229 230 $group = &$data['groups'][$trigger_group['groupid']]; 231 232 if (in_array($filter_ext_ack, [EXTACK_OPTION_ALL, EXTACK_OPTION_BOTH])) { 233 if ($group['stats'][$problem['severity']]['count'] < ZBX_WIDGET_ROWS) { 234 $group['stats'][$problem['severity']]['problems'][] = $problem; 235 $visible_problems[$eventid] = ['eventid' => $eventid]; 236 } 237 238 $group['stats'][$problem['severity']]['count']++; 239 } 240 241 if (in_array($filter_ext_ack, [EXTACK_OPTION_UNACK, EXTACK_OPTION_BOTH]) 242 && $problem['acknowledged'] == EVENT_NOT_ACKNOWLEDGED) { 243 if ($group['stats'][$problem['severity']]['count_unack'] < ZBX_WIDGET_ROWS) { 244 $group['stats'][$problem['severity']]['problems_unack'][] = $problem; 245 $visible_problems[$eventid] = ['eventid' => $eventid]; 246 } 247 248 $group['stats'][$problem['severity']]['count_unack']++; 249 } 250 251 $group['has_problems'] = true; 252 } 253 unset($group); 254 } 255 256 // actions & tags 257 $problems_data = API::Problem()->get([ 258 'output' => ['eventid', 'r_eventid', 'clock', 'objectid', 'severity'], 259 'eventids' => array_keys($visible_problems), 260 'selectAcknowledges' => ['userid', 'clock', 'message', 'action', 'old_severity', 'new_severity'], 261 'selectTags' => ['tag', 'value'], 262 'preservekeys' => true 263 ]); 264 265 // Remove problems that were resolved between requests or set tags. 266 foreach ($data['groups'] as $groupid => &$group) { 267 foreach ($group['stats'] as $severity => &$stat) { 268 foreach (['problems', 'problems_unack'] as $key) { 269 foreach ($stat[$key] as $event_no => &$problem) { 270 if (array_key_exists($problem['eventid'], $problems_data)) { 271 $problem['tags'] = $problems_data[$problem['eventid']]['tags']; 272 } 273 else { 274 if ($key === 'problems') { 275 $data['groups'][$groupid]['stats'][$severity]['count']--; 276 } 277 else { 278 $data['groups'][$groupid]['stats'][$severity]['count_unack']--; 279 } 280 unset($data['groups'][$groupid]['stats'][$severity][$key][$event_no]); 281 } 282 } 283 unset($problem); 284 } 285 } 286 unset($stat); 287 } 288 unset($group); 289 290 // actions 291 // Possible performance improvement: one API call may be saved, if r_clock for problem will be used. 292 $actions = getEventsActionsIconsData($problems_data, $data['triggers']); 293 $data['actions'] = [ 294 'all_actions' => $actions['data'], 295 'users' => API::User()->get([ 296 'output' => ['username', 'name', 'surname'], 297 'userids' => array_keys($actions['userids']), 298 'preservekeys' => true 299 ]) 300 ]; 301 302 if (array_key_exists('show_opdata', $filter) && $filter['show_opdata'] != OPERATIONAL_DATA_SHOW_NONE) { 303 $maked_data = CScreenProblem::makeData( 304 ['problems' => $problems_data, 'triggers' => $data['triggers']], 305 ['show' => 0, 'details' => 0, 'show_opdata' => $filter['show_opdata']] 306 ); 307 $data['triggers'] = $maked_data['triggers']; 308 } 309 } 310 311 return $data; 312} 313 314/** 315 * @param array $data 316 * @param array $data['groups'] 317 * @param string $data['groups'][]['groupid'] 318 * @param string $data['groups'][]['name'] 319 * @param bool $data['groups'][]['has_problems'] 320 * @param array $data['groups'][]['stats'] 321 * @param int $data['groups'][]['stats'][]['count'] 322 * @param array $data['groups'][]['stats'][]['problems'] 323 * @param int $data['groups'][]['stats'][]['count_unack'] 324 * @param array $data['groups'][]['stats'][]['problems_unack'] 325 * 326 * @return array 327 */ 328function getSystemStatusTotals(array $data) { 329 $groups_totals = [ 330 0 => [ 331 'groupid' => 0, 332 'stats' => [] 333 ] 334 ]; 335 336 foreach ($data['stats'] as $severity => $value) { 337 $groups_totals[0]['stats'][$severity] = [ 338 'count' => $value['count'], 339 'problems' => [], 340 'count_unack' => $value['count_unack'], 341 'problems_unack' => [] 342 ]; 343 } 344 345 foreach ($data['groups'] as $group) { 346 foreach ($group['stats'] as $severity => $stat) { 347 foreach ($stat['problems'] as $problem) { 348 $groups_totals[0]['stats'][$severity]['problems'][$problem['eventid']] = $problem; 349 } 350 foreach ($stat['problems_unack'] as $problem) { 351 $groups_totals[0]['stats'][$severity]['problems_unack'][$problem['eventid']] = $problem; 352 } 353 } 354 } 355 356 return $groups_totals; 357} 358 359/** 360 * @param array $data 361 * @param array $data['data'] 362 * @param array $data['data']['groups'] 363 * @param array $data['data']['groups'][]['stats'] 364 * @param array $data['filter'] 365 * @param array $data['filter']['severities'] 366 * @param array $data['allowed'] 367 * @param bool $data['allowed']['ui_problems'] 368 * @param bool $data['allowed']['add_comments'] 369 * @param bool $data['allowed']['change_severity'] 370 * @param bool $data['allowed']['acknowledge'] 371 * @param bool $data['allowed']['close'] 372 * @param bool $hide_empty_groups 373 * @param CUrl $groupurl 374 * 375 * @return CTableInfo 376 */ 377function makeSeverityTable(array $data, $hide_empty_groups = false, CUrl $groupurl = null) { 378 $table = new CTableInfo(); 379 380 foreach ($data['data']['groups'] as $group) { 381 if ($hide_empty_groups && !$group['has_problems']) { 382 // Skip row. 383 continue; 384 } 385 386 if ($data['allowed']['ui_problems']) { 387 $groupurl->setArgument('groupids', [$group['groupid']]); 388 $row = [new CLink($group['name'], $groupurl->getUrl())]; 389 } 390 else { 391 $row = [$group['name']]; 392 } 393 394 foreach ($group['stats'] as $severity => $stat) { 395 if ($data['filter']['severities'] && !in_array($severity, $data['filter']['severities'])) { 396 // Skip cell. 397 continue; 398 } 399 400 $row[] = getSeverityTableCell($severity, $data, $stat); 401 } 402 403 $table->addRow($row); 404 } 405 406 return $table; 407} 408 409/** 410 * @param array $data 411 * @param array $data['data'] 412 * @param array $data['data']['groups'] 413 * @param array $data['data']['groups'][]['stats'] 414 * @param array $data['filter'] 415 * @param array $data['filter']['severities'] 416 * @param array $data['allowed'] 417 * @param bool $data['allowed']['ui_problems'] 418 * @param bool $data['allowed']['add_comments'] 419 * @param bool $data['allowed']['change_severity'] 420 * @param bool $data['allowed']['acknowledge'] 421 * @param bool $data['allowed']['close'] 422 * 423 * @return CDiv 424 */ 425function makeSeverityTotals(array $data) { 426 $table = new CDiv(); 427 428 foreach ($data['data']['groups'] as $group) { 429 foreach ($group['stats'] as $severity => $stat) { 430 if ($data['filter']['severities'] && !in_array($severity, $data['filter']['severities'])) { 431 // Skip cell. 432 continue; 433 } 434 $table->addItem(getSeverityTableCell($severity, $data, $stat, true)); 435 } 436 } 437 438 return $table; 439} 440 441/** 442 * @param int $severity 443 * @param array $data 444 * @param array $data['data'] 445 * @param array $data['data']['triggers'] 446 * @param array $data['data']['actions'] 447 * @param array $data['filter'] 448 * @param array $data['filter']['ext_ack'] 449 * @param array $data['severity_names'] 450 * @param array $data['allowed'] 451 * @param bool $data['allowed']['ui_problems'] 452 * @param bool $data['allowed']['add_comments'] 453 * @param bool $data['allowed']['change_severity'] 454 * @param bool $data['allowed']['acknowledge'] 455 * @param bool $data['allowed']['close'] 456 * @param array $stat 457 * @param int $stat['count'] 458 * @param array $stat['problems'] 459 * @param int $stat['count_unack'] 460 * @param array $stat['problems_unack'] 461 * @param bool $is_total 462 * 463 * @return CCol|string 464 */ 465function getSeverityTableCell($severity, array $data, array $stat, $is_total = false) { 466 if (!$is_total && $stat['count'] == 0 && $stat['count_unack'] == 0) { 467 return ''; 468 } 469 470 $severity_name = $is_total ? ' '.getSeverityName($severity) : ''; 471 $ext_ack = array_key_exists('ext_ack', $data['filter']) ? $data['filter']['ext_ack'] : EXTACK_OPTION_ALL; 472 473 $allTriggersNum = $stat['count']; 474 if ($allTriggersNum) { 475 $allTriggersNum = (new CLinkAction($allTriggersNum)) 476 ->setHint(makeProblemsPopup($stat['problems'], $data['data']['triggers'], $data['data']['actions'], 477 $data['filter'], $data['allowed'] 478 )); 479 } 480 481 $unackTriggersNum = $stat['count_unack']; 482 if ($unackTriggersNum) { 483 $unackTriggersNum = (new CLinkAction($unackTriggersNum)) 484 ->setHint(makeProblemsPopup($stat['problems_unack'], $data['data']['triggers'], $data['data']['actions'], 485 $data['filter'], $data['allowed'] 486 )); 487 } 488 489 switch ($ext_ack) { 490 case EXTACK_OPTION_ALL: 491 return getSeverityCell($severity, [ 492 (new CSpan($allTriggersNum))->addClass(ZBX_STYLE_TOTALS_LIST_COUNT), 493 $severity_name 494 ], false, $is_total); 495 496 case EXTACK_OPTION_UNACK: 497 return getSeverityCell($severity, [ 498 (new CSpan($unackTriggersNum))->addClass(ZBX_STYLE_TOTALS_LIST_COUNT), 499 $severity_name 500 ], false, $is_total); 501 502 case EXTACK_OPTION_BOTH: 503 return getSeverityCell($severity, [ 504 (new CSpan([$unackTriggersNum, ' '._('of').' ', $allTriggersNum])) 505 ->addClass(ZBX_STYLE_TOTALS_LIST_COUNT), 506 $severity_name 507 ], false, $is_total); 508 509 default: 510 return ''; 511 } 512} 513 514function make_status_of_zbx() { 515 if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) { 516 global $ZBX_SERVER, $ZBX_SERVER_PORT; 517 518 $server_details = $ZBX_SERVER.':'.$ZBX_SERVER_PORT; 519 } 520 else { 521 $server_details = ''; 522 } 523 524 $table = (new CTableInfo()) 525 ->setHeader([_('Parameter'), _('Value'), _('Details')]) 526 ->setHeadingColumn(0); 527 528 $status = get_status(); 529 530 $table 531 ->addRow([_('Zabbix server is running'), 532 (new CSpan($status['is_running'] ? _('Yes') : _('No'))) 533 ->addClass($status['is_running'] ? ZBX_STYLE_GREEN : ZBX_STYLE_RED), 534 $server_details 535 ]) 536 ->addRow([_('Number of hosts (enabled/disabled)'), 537 $status['has_status'] ? $status['hosts_count'] : '', 538 $status['has_status'] 539 ? [ 540 (new CSpan($status['hosts_count_monitored']))->addClass(ZBX_STYLE_GREEN), ' / ', 541 (new CSpan($status['hosts_count_not_monitored']))->addClass(ZBX_STYLE_RED) 542 ] 543 : '' 544 ]) 545 ->addRow([_('Number of templates'), 546 $status['has_status'] ? $status['hosts_count_template'] : '', '' 547 ]); 548 549 $title = (new CSpan(_('Number of items (enabled/disabled/not supported)'))) 550 ->setTitle(_('Only items assigned to enabled hosts are counted')); 551 $table->addRow([$title, $status['has_status'] ? $status['items_count'] : '', 552 $status['has_status'] 553 ? [ 554 (new CSpan($status['items_count_monitored']))->addClass(ZBX_STYLE_GREEN), ' / ', 555 (new CSpan($status['items_count_disabled']))->addClass(ZBX_STYLE_RED), ' / ', 556 (new CSpan($status['items_count_not_supported']))->addClass(ZBX_STYLE_GREY) 557 ] 558 : '' 559 ]); 560 $title = (new CSpan(_('Number of triggers (enabled/disabled [problem/ok])'))) 561 ->setTitle(_('Only triggers assigned to enabled hosts and depending on enabled items are counted')); 562 $table->addRow([$title, $status['has_status'] ? $status['triggers_count'] : '', 563 $status['has_status'] 564 ? [ 565 $status['triggers_count_enabled'], ' / ', 566 $status['triggers_count_disabled'], ' [', 567 (new CSpan($status['triggers_count_on']))->addClass(ZBX_STYLE_RED), ' / ', 568 (new CSpan($status['triggers_count_off']))->addClass(ZBX_STYLE_GREEN), ']' 569 ] 570 : '' 571 ]); 572 $table->addRow([_('Number of users (online)'), $status['has_status'] ? $status['users_count'] : '', 573 $status['has_status'] ? (new CSpan($status['users_online']))->addClass(ZBX_STYLE_GREEN) : '' 574 ]); 575 if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) { 576 $table->addRow([_('Required server performance, new values per second'), 577 ($status['has_status'] && array_key_exists('vps_total', $status)) ? round($status['vps_total'], 2) : '', '' 578 ]); 579 } 580 581 // Check requirements. 582 if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) { 583 $setup = new CFrontendSetup(); 584 $reqs = $setup->checkRequirements(); 585 $reqs[] = $setup->checkSslFiles(); 586 587 foreach ($reqs as $req) { 588 if ($req['result'] == CFrontendSetup::CHECK_FATAL) { 589 $table->addRow( 590 (new CRow([$req['name'], $req['current'], $req['error']]))->addClass(ZBX_STYLE_RED) 591 ); 592 } 593 } 594 595 $db = DB::getDbBackend(); 596 597 if (!$db->checkEncoding()) { 598 $table->addRow( 599 (new CRow((new CCol($db->getWarning()))->setAttribute('colspan', 3)))->addClass(ZBX_STYLE_RED) 600 ); 601 } 602 } 603 604 // Warn if database history tables have not been upgraded. 605 global $DB; 606 607 if (!$DB['DOUBLE_IEEE754']) { 608 $table->addRow([ 609 _('Database history tables upgraded'), 610 (new CSpan(_('No')))->addClass(ZBX_STYLE_RED), 611 '' 612 ]); 613 } 614 615 // Check DB version. 616 if (CWebUser::getType() == USER_TYPE_SUPER_ADMIN) { 617 $dbversion_status = CSettingsHelper::getGlobal(CSettingsHelper::DBVERSION_STATUS); 618 619 if ($dbversion_status !== '') { 620 $dbversion_status = json_decode($dbversion_status); 621 622 foreach ($dbversion_status as $dbversion) { 623 if ($dbversion->flag != DB_VERSION_SUPPORTED) { 624 switch ($dbversion->flag) { 625 case DB_VERSION_LOWER_THAN_MINIMUM: 626 $error = _s('Minimum required %1$s database version is %2$s.', $dbversion->database, 627 $dbversion->min_version 628 ); 629 break; 630 631 case DB_VERSION_HIGHER_THAN_MAXIMUM: 632 $error = _s('Maximum required %1$s database version is %2$s.', $dbversion->database, 633 $dbversion->max_version 634 ); 635 break; 636 637 case DB_VERSION_FAILED_TO_RETRIEVE: 638 $error = _('Unable to retrieve database version.'); 639 $dbversion->current_version = ''; 640 break; 641 } 642 643 $table->addRow( 644 (new CRow([$dbversion->database, $dbversion->current_version, $error]))->addClass(ZBX_STYLE_RED) 645 ); 646 } 647 } 648 } 649 } 650 651 return $table; 652} 653 654/** 655 * Generate table for dashboard triggers popup. 656 * 657 * @param array $problems 658 * @param string $problems[]['objectid'] 659 * @param int $problems[]['clock'] 660 * @param int $problems[]['ns'] 661 * @param string $problems[]['r_eventid'] 662 * @param string $problems[]['acknowledged'] 663 * @param array $problems[]['acknowledges'] 664 * @param string $problems[]['acknowledges'][]['action'] 665 * @param array $problems[]['severity'] 666 * @param array $problems[]['suppression_data'] 667 * @param array $problems[]['tags'] 668 * @param string $problems[]['tags'][]['tag'] 669 * @param string $problems[]['tags'][]['value'] 670 * @param array $triggers 671 * @param string $triggers[<triggerid>]['expression'] 672 * @param string $triggers[<triggerid>]['description'] 673 * @param string $triggers[<triggerid>]['manual_close'] 674 * @param array $triggers[<triggerid>]['hosts'] 675 * @param string $triggers[<triggerid>]['hosts'][]['name'] 676 * @param string $triggers[<triggerid>]['opdata'] 677 * @param array $actions 678 * @param array $filter 679 * @param array $filter['show_suppressed'] (optional) 680 * @param array $filter['show_timeline'] (optional) 681 * @param array $filter['show_opdata'] (optional) 682 * @param array $allowed 683 * @param bool $allowed['ui_problems'] 684 * @param bool $allowed['add_comments'] 685 * @param bool $allowed['change_severity'] 686 * @param bool $allowed['acknowledge'] 687 * @param bool $allowed['close'] 688 * 689 * @return CTableInfo 690 */ 691function makeProblemsPopup(array $problems, array $triggers, array $actions, array $filter, array $allowed) { 692 $url_details = $allowed['ui_problems'] 693 ? (new CUrl('tr_events.php')) 694 ->setArgument('triggerid', '') 695 ->setArgument('eventid', '') 696 : null; 697 698 $header_time = new CColHeader([_('Time'), (new CSpan())->addClass(ZBX_STYLE_ARROW_DOWN)]); 699 700 $show_timeline = (array_key_exists('show_timeline', $filter) && $filter['show_timeline']); 701 $show_opdata = (array_key_exists('show_opdata', $filter)) ? $filter['show_opdata'] : OPERATIONAL_DATA_SHOW_NONE; 702 703 if ($show_timeline) { 704 $header = [ 705 $header_time->addClass(ZBX_STYLE_RIGHT), 706 (new CColHeader())->addClass(ZBX_STYLE_TIMELINE_TH), 707 (new CColHeader())->addClass(ZBX_STYLE_TIMELINE_TH) 708 ]; 709 } 710 else { 711 $header = [$header_time]; 712 } 713 714 $table = (new CTableInfo()) 715 ->setHeader(array_merge($header, [ 716 _('Info'), 717 _('Host'), 718 _('Problem'), 719 ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) ? _('Operational data') : null, 720 _('Duration'), 721 _('Ack'), 722 _('Actions'), 723 _('Tags') 724 ])); 725 726 $today = strtotime('today'); 727 $last_clock = 0; 728 729 // Unset triggers, which missing in problems array. 730 if ($problems) { 731 $objectids = []; 732 733 foreach ($problems as $problem) { 734 $objectids[$problem['objectid']] = true; 735 } 736 737 $triggers = array_intersect_key($triggers, $objectids); 738 } 739 740 $triggers_hosts = getTriggersHostsList($triggers); 741 $triggers_hosts = makeTriggersHostsList($triggers_hosts); 742 743 $tags = makeTags($problems); 744 745 if (array_key_exists('show_suppressed', $filter) && $filter['show_suppressed']) { 746 CScreenProblem::addMaintenanceNames($problems); 747 } 748 749 foreach ($problems as $problem) { 750 $trigger = $triggers[$problem['objectid']]; 751 752 $cell_clock = ($problem['clock'] >= $today) 753 ? zbx_date2str(TIME_FORMAT_SECONDS, $problem['clock']) 754 : zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['clock']); 755 756 if ($url_details !== null) { 757 $url_details 758 ->setArgument('triggerid', $problem['objectid']) 759 ->setArgument('eventid', $problem['eventid']); 760 $cell_clock = new CCol(new CLink($cell_clock, $url_details)); 761 } 762 else { 763 $cell_clock = new CCol($cell_clock); 764 } 765 766 if ($show_timeline) { 767 if ($last_clock != 0) { 768 CScreenProblem::addTimelineBreakpoint($table, $last_clock, $problem['clock'], ZBX_SORT_DOWN); 769 } 770 $last_clock = $problem['clock']; 771 772 $row = [ 773 $cell_clock->addClass(ZBX_STYLE_TIMELINE_DATE), 774 (new CCol()) 775 ->addClass(ZBX_STYLE_TIMELINE_AXIS) 776 ->addClass(ZBX_STYLE_TIMELINE_DOT), 777 (new CCol())->addClass(ZBX_STYLE_TIMELINE_TD) 778 ]; 779 } 780 else { 781 $row = [ 782 $cell_clock 783 ->addClass(ZBX_STYLE_NOWRAP) 784 ->addClass(ZBX_STYLE_RIGHT) 785 ]; 786 } 787 788 $info_icons = []; 789 if (array_key_exists('suppression_data', $problem) && $problem['suppression_data']) { 790 $info_icons[] = makeSuppressedProblemIcon($problem['suppression_data']); 791 } 792 793 // operational data 794 $opdata = null; 795 if ($show_opdata != OPERATIONAL_DATA_SHOW_NONE) { 796 797 if ($trigger['opdata'] === '') { 798 if ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) { 799 $opdata = (new CCol(CScreenProblem::getLatestValues($trigger['items'])))->addClass('latest-values'); 800 } 801 } 802 else { 803 $opdata = CMacrosResolverHelper::resolveTriggerOpdata( 804 [ 805 'triggerid' => $trigger['triggerid'], 806 'expression' => $trigger['expression'], 807 'opdata' => $trigger['opdata'], 808 'clock' => $problem['clock'], 809 'ns' => $problem['ns'] 810 ], 811 [ 812 'events' => true, 813 'html' => true 814 ] 815 ); 816 817 if ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) { 818 $opdata = (new CCol($opdata)) 819 ->addClass('opdata') 820 ->addClass(ZBX_STYLE_WORDWRAP); 821 } 822 } 823 } 824 825 $can_be_closed = ($trigger['manual_close'] == ZBX_TRIGGER_MANUAL_CLOSE_ALLOWED && $allowed['close']); 826 827 if ($problem['r_eventid'] != 0) { 828 $can_be_closed = false; 829 } 830 else { 831 foreach ($problem['acknowledges'] as $acknowledge) { 832 if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) { 833 $can_be_closed = false; 834 break; 835 } 836 } 837 } 838 839 // Create acknowledge link. 840 $is_acknowledged = ($problem['acknowledged'] == EVENT_ACKNOWLEDGED); 841 $problem_update_link = ($allowed['add_comments'] || $allowed['change_severity'] || $allowed['acknowledge'] 842 || $can_be_closed) 843 ? (new CLink($is_acknowledged ? _('Yes') : _('No'))) 844 ->addClass($is_acknowledged ? ZBX_STYLE_GREEN : ZBX_STYLE_RED) 845 ->addClass(ZBX_STYLE_LINK_ALT) 846 ->onClick('acknowledgePopUp('.json_encode(['eventids' => [$problem['eventid']]]).', this);') 847 : (new CSpan($is_acknowledged ? _('Yes') : _('No')))->addClass( 848 $is_acknowledged ? ZBX_STYLE_GREEN : ZBX_STYLE_RED 849 ); 850 851 $table->addRow(array_merge($row, [ 852 makeInformationList($info_icons), 853 $triggers_hosts[$trigger['triggerid']], 854 getSeverityCell($problem['severity'], 855 (($show_opdata == OPERATIONAL_DATA_SHOW_WITH_PROBLEM && $opdata) 856 ? [$problem['name'], ' (', $opdata, ')'] 857 : $problem['name'] 858 ) 859 ), 860 ($show_opdata == OPERATIONAL_DATA_SHOW_SEPARATELY) ? $opdata : null, 861 zbx_date2age($problem['clock']), 862 $problem_update_link, 863 makeEventActionsIcons($problem['eventid'], $actions['all_actions'], $actions['users']), 864 $tags[$problem['eventid']] 865 ])); 866 } 867 868 return $table; 869} 870