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 22$table = (new CTableInfo()) 23 ->setHeader([ 24 _('Host group'), 25 _('Without problems'), 26 _('With problems'), 27 _('Total') 28 ]); 29 30// get host groups 31$groups = API::HostGroup()->get([ 32 'output' => ['groupid', 'name'], 33 'groupids' => $data['filter']['groupids'], 34 'hostids' => isset($data['filter']['hostids']) ? $data['filter']['hostids'] : null, 35 'monitored_hosts' => true, 36 'preservekeys' => true 37]); 38CArrayHelper::sort($groups, ['name']); 39 40// get hosts 41$hosts = API::Host()->get([ 42 'output' => ['hostid', 'name'], 43 'selectGroups' => ['groupid'], 44 'groupids' => array_keys($groups), 45 'hostids' => isset($data['filter']['hostids']) ? $data['filter']['hostids'] : null, 46 'filter' => ['maintenance_status' => $data['filter']['maintenance']], 47 'monitored_hosts' => true, 48 'preservekeys' => true 49]); 50CArrayHelper::sort($hosts, ['name']); 51 52// get triggers 53$triggers = API::Trigger()->get([ 54 'output' => ['triggerid', 'priority'], 55 'selectHosts' => ['hostid'], 56 'search' => ($data['filter']['trigger_name'] !== '') ? ['description' => $data['filter']['trigger_name']] : null, 57 'filter' => [ 58 'priority' => $data['filter']['severity'], 59 'value' => TRIGGER_VALUE_TRUE 60 ], 61 'maintenance' => $data['filter']['maintenance'], 62 'monitored' => true 63]); 64 65if ($data['filter']['extAck']) { 66 $hosts_with_unack_triggers = []; 67 68 $triggers_unack = API::Trigger()->get([ 69 'output' => ['triggerid'], 70 'selectHosts' => ['hostid'], 71 'search' => ($data['filter']['trigger_name'] !== '') 72 ? ['description' => $data['filter']['trigger_name']] 73 : null, 74 'filter' => [ 75 'priority' => $data['filter']['severity'], 76 'value' => TRIGGER_VALUE_TRUE 77 ], 78 'withLastEventUnacknowledged' => true, 79 'maintenance' => $data['filter']['maintenance'], 80 'monitored' => true, 81 'preservekeys' => true 82 ]); 83 84 foreach ($triggers_unack as $tunack) { 85 foreach ($tunack['hosts'] as $unack_host) { 86 $hosts_with_unack_triggers[$unack_host['hostid']] = $unack_host['hostid']; 87 } 88 } 89} 90 91$hosts_data = []; 92$problematic_host_list = []; 93$lastUnack_host_list = []; 94$highest_severity = []; 95$highest_severity2 = []; 96 97foreach ($triggers as $trigger) { 98 foreach ($trigger['hosts'] as $trigger_host) { 99 if (!isset($hosts[$trigger_host['hostid']])) { 100 continue; 101 } 102 else { 103 $host = $hosts[$trigger_host['hostid']]; 104 } 105 106 if ($data['filter']['extAck'] && array_key_exists($host['hostid'], $hosts_with_unack_triggers)) { 107 if (!isset($lastUnack_host_list[$host['hostid']])) { 108 $lastUnack_host_list[$host['hostid']] = []; 109 $lastUnack_host_list[$host['hostid']]['host'] = $host['name']; 110 $lastUnack_host_list[$host['hostid']]['hostid'] = $host['hostid']; 111 $lastUnack_host_list[$host['hostid']]['severities'] = []; 112 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_DISASTER] = 0; 113 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_HIGH] = 0; 114 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_AVERAGE] = 0; 115 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_WARNING] = 0; 116 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_INFORMATION] = 0; 117 $lastUnack_host_list[$host['hostid']]['severities'][TRIGGER_SEVERITY_NOT_CLASSIFIED] = 0; 118 } 119 if (isset($triggers_unack[$trigger['triggerid']])) { 120 $lastUnack_host_list[$host['hostid']]['severities'][$trigger['priority']]++; 121 } 122 123 foreach ($host['groups'] as $gnum => $group) { 124 if (!isset($highest_severity2[$group['groupid']])) { 125 $highest_severity2[$group['groupid']] = 0; 126 } 127 128 if ($data['filter']['extAck'] == EXTACK_OPTION_UNACK) { 129 if ($trigger['priority'] > $highest_severity2[$group['groupid']] 130 && array_key_exists($trigger['triggerid'], $triggers_unack)) { 131 $highest_severity2[$group['groupid']] = $trigger['priority']; 132 } 133 } 134 elseif ($trigger['priority'] > $highest_severity2[$group['groupid']]) { 135 $highest_severity2[$group['groupid']] = $trigger['priority']; 136 } 137 138 if (!isset($hosts_data[$group['groupid']])) { 139 $hosts_data[$group['groupid']] = [ 140 'problematic' => 0, 141 'ok' => 0, 142 'lastUnack' => 0, 143 'hostids_all' => [], 144 'hostids_unack' => [] 145 ]; 146 } 147 148 if (!isset($hosts_data[$group['groupid']]['hostids_unack'][$host['hostid']])) { 149 $hosts_data[$group['groupid']]['hostids_unack'][$host['hostid']] = $host['hostid']; 150 $hosts_data[$group['groupid']]['lastUnack']++; 151 } 152 } 153 } 154 155 if (!isset($problematic_host_list[$host['hostid']])) { 156 $problematic_host_list[$host['hostid']] = []; 157 $problematic_host_list[$host['hostid']]['host'] = $host['name']; 158 $problematic_host_list[$host['hostid']]['hostid'] = $host['hostid']; 159 160 $problematic_host_list[$host['hostid']]['severities'] = []; 161 162 for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { 163 $problematic_host_list[$host['hostid']]['severities'][$severity] = 0; 164 } 165 166 krsort($problematic_host_list[$host['hostid']]['severities']); 167 } 168 $problematic_host_list[$host['hostid']]['severities'][$trigger['priority']]++; 169 170 foreach ($host['groups'] as $gnum => $group) { 171 if (!isset($highest_severity[$group['groupid']])) { 172 $highest_severity[$group['groupid']] = 0; 173 } 174 175 if ($trigger['priority'] > $highest_severity[$group['groupid']]) { 176 $highest_severity[$group['groupid']] = $trigger['priority']; 177 } 178 179 if (!isset($hosts_data[$group['groupid']])) { 180 $hosts_data[$group['groupid']] = [ 181 'problematic' => 0, 182 'ok' => 0, 183 'lastUnack' => 0, 184 'hostids_all' => [], 185 'hostids_unack' => [] 186 ]; 187 } 188 189 if (!isset($hosts_data[$group['groupid']]['hostids_all'][$host['hostid']])) { 190 $hosts_data[$group['groupid']]['hostids_all'][$host['hostid']] = $host['hostid']; 191 192 /* 193 * Display acknowledged problem triggers in "Without problems" column when filter dashboard is 194 * enabled and is set to display "Unacknowledged only". Host and trigger must not be in 195 * unacknowledged lists. Count as problematic host otherwise. 196 */ 197 if ($data['filter']['extAck'] == EXTACK_OPTION_UNACK 198 && !array_key_exists($host['hostid'], $hosts_with_unack_triggers) 199 && !array_key_exists($trigger['triggerid'], $triggers_unack)) { 200 $hosts_data[$group['groupid']]['ok']++; 201 } 202 else { 203 $hosts_data[$group['groupid']]['problematic']++; 204 } 205 } 206 } 207 } 208} 209 210foreach ($hosts as $host) { 211 foreach ($host['groups'] as $group) { 212 if (!isset($groups[$group['groupid']])) { 213 continue; 214 } 215 216 if (!isset($groups[$group['groupid']]['hosts'])) { 217 $groups[$group['groupid']]['hosts'] = []; 218 } 219 $groups[$group['groupid']]['hosts'][$host['hostid']] = ['hostid' => $host['hostid']]; 220 221 if (!isset($highest_severity[$group['groupid']])) { 222 $highest_severity[$group['groupid']] = 0; 223 } 224 225 if (!isset($hosts_data[$group['groupid']])) { 226 $hosts_data[$group['groupid']] = ['problematic' => 0, 'ok' => 0, 'lastUnack' => 0]; 227 } 228 229 if (!isset($problematic_host_list[$host['hostid']])) { 230 $hosts_data[$group['groupid']]['ok']++; 231 } 232 } 233} 234 235foreach ($groups as $group) { 236 if (!isset($hosts_data[$group['groupid']])) { 237 continue; 238 } 239 240 $group_row = new CRow(); 241 242 $name = new CLink($group['name'], 'tr_status.php?filter_set=1&groupid='.$group['groupid'].'&hostid=0'); 243 244 $group_row->addItem($name); 245 $group_row->addItem((new CCol($hosts_data[$group['groupid']]['ok']))->addClass(ZBX_STYLE_NORMAL_BG)); 246 247 if ($data['filter']['extAck']) { 248 if ($hosts_data[$group['groupid']]['lastUnack']) { 249 $table_inf = new CTableInfo(); 250 251 // set trigger severities as table header starting from highest severity 252 $header = []; 253 254 for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { 255 $header[] = ($data['filter']['severity'] === null || isset($data['filter']['severity'][$severity])) 256 ? getSeverityName($severity, $data['config']) 257 : null; 258 } 259 260 krsort($header); 261 array_unshift($header, _('Host')); 262 263 $table_inf->setHeader($header); 264 265 $popup_rows = 0; 266 267 foreach ($group['hosts'] as $host) { 268 $hostid = $host['hostid']; 269 if (!isset($lastUnack_host_list[$hostid])) { 270 continue; 271 } 272 273 $host_data = $lastUnack_host_list[$hostid]; 274 275 $r = new CRow(); 276 $r->addItem( 277 (new CCol( 278 new CLink($host_data['host'], 279 'tr_status.php?filter_set=1&groupid='.$group['groupid'].'&hostid='.$hostid 280 ) 281 ))->addClass(ZBX_STYLE_NOWRAP) 282 ); 283 284 foreach ($lastUnack_host_list[$host['hostid']]['severities'] as $severity => $trigger_count) { 285 if (!is_null($data['filter']['severity']) && !isset($data['filter']['severity'][$severity])) { 286 continue; 287 } 288 $r->addItem((new CCol($trigger_count))->addClass(getSeverityStyle($severity, $trigger_count))); 289 } 290 $table_inf->addRow($r); 291 292 if (++$popup_rows == ZBX_WIDGET_ROWS) { 293 break; 294 } 295 } 296 $lastUnack_count = (new CSpan($hosts_data[$group['groupid']]['lastUnack'])) 297 ->addClass(ZBX_STYLE_LINK_ACTION) 298 ->setHint($table_inf); 299 } 300 else { 301 $lastUnack_count = 0; 302 } 303 } 304 305 // if hostgroup contains problematic hosts, hint should be built 306 if ($hosts_data[$group['groupid']]['problematic']) { 307 $table_inf = new CTableInfo(); 308 309 // set trigger severities as table header starting from highest severity 310 $header = []; 311 312 for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { 313 $header[] = ($data['filter']['severity'] === null || isset($data['filter']['severity'][$severity])) 314 ? getSeverityName($severity, $data['config']) 315 : null; 316 } 317 318 krsort($header); 319 array_unshift($header, _('Host')); 320 321 $table_inf->setHeader($header); 322 323 $popup_rows = 0; 324 325 foreach ($group['hosts'] as $host) { 326 $hostid = $host['hostid']; 327 if (!isset($problematic_host_list[$hostid])) { 328 continue; 329 } 330 331 $host_data = $problematic_host_list[$hostid]; 332 333 $r = new CRow(); 334 $r->addItem(new CLink($host_data['host'], 335 'tr_status.php?filter_set=1&groupid='.$group['groupid'].'&hostid='.$hostid 336 )); 337 338 foreach ($problematic_host_list[$host['hostid']]['severities'] as $severity => $trigger_count) { 339 if (!is_null($data['filter']['severity']) && !isset($data['filter']['severity'][$severity])) { 340 continue; 341 } 342 $r->addItem((new CCol($trigger_count))->addClass(getSeverityStyle($severity, $trigger_count))); 343 } 344 $table_inf->addRow($r); 345 346 if (++$popup_rows == ZBX_WIDGET_ROWS) { 347 break; 348 } 349 } 350 $problematic_count = (new CSpan($hosts_data[$group['groupid']]['problematic'])) 351 ->addClass(ZBX_STYLE_LINK_ACTION) 352 ->setHint($table_inf); 353 } 354 else { 355 $problematic_count = 0; 356 } 357 358 switch ($data['filter']['extAck']) { 359 case EXTACK_OPTION_ALL: 360 $group_row->addItem((new CCol($problematic_count)) 361 ->addClass(getSeverityStyle($highest_severity[$group['groupid']], $hosts_data[$group['groupid']]['problematic'])) 362 ); 363 $group_row->addItem($hosts_data[$group['groupid']]['problematic'] + $hosts_data[$group['groupid']]['ok']); 364 break; 365 case EXTACK_OPTION_UNACK: 366 $group_row->addItem((new CCol($lastUnack_count)) 367 ->addClass(getSeverityStyle( 368 isset($highest_severity2[$group['groupid']]) ? $highest_severity2[$group['groupid']] : 0, 369 $hosts_data[$group['groupid']]['lastUnack'] 370 )) 371 ); 372 $group_row->addItem($hosts_data[$group['groupid']]['lastUnack'] + $hosts_data[$group['groupid']]['ok']); 373 break; 374 case EXTACK_OPTION_BOTH: 375 $unackspan = $lastUnack_count ? [$lastUnack_count, ' '._('of').' '] : null; 376 $group_row->addItem((new CCol([$unackspan, $problematic_count])) 377 ->addClass(getSeverityStyle( 378 $highest_severity[$group['groupid']], $hosts_data[$group['groupid']]['problematic'] 379 )) 380 ); 381 $group_row->addItem($hosts_data[$group['groupid']]['problematic'] + $hosts_data[$group['groupid']]['ok']); 382 break; 383 } 384 385 $table->addRow($group_row); 386} 387 388$output = [ 389 'header' => _('Host status'), 390 'body' => (new CDiv([getMessages(), $table]))->toString(), 391 'footer' => (new CListItem(_s('Updated: %s', zbx_date2str(TIME_FORMAT_SECONDS))))->toString() 392]; 393 394if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { 395 CProfiler::getInstance()->stop(); 396 $output['debug'] = CProfiler::getInstance()->make()->toString(); 397} 398 399echo (new CJson())->encode($output); 400