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__).'/include/config.inc.php'; 23require_once dirname(__FILE__).'/include/hosts.inc.php'; 24 25$page['title'] = _('Availability report'); 26$page['file'] = 'report2.php'; 27$page['scripts'] = ['class.calendar.js']; 28$page['type'] = detect_page_type(PAGE_TYPE_HTML); 29 30require_once dirname(__FILE__).'/include/page_header.php'; 31 32// VAR TYPE OPTIONAL FLAGS VALIDATION EXCEPTION 33$fields = [ 34 'mode' => [T_ZBX_INT, O_OPT, P_SYS, IN('0,1'), null], 35 'hostgroupid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 36 'tpl_triggerid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 37 'triggerid' => [T_ZBX_INT, O_OPT, P_SYS|P_NZERO, DB_ID, null], 38 // filter 39 'filter_groupid'=> [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 40 'filter_hostid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 41 'filter_rst'=> [T_ZBX_STR, O_OPT, P_SYS, null, null], 42 'filter_set' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 43 'filter_timesince' => [T_ZBX_STR, O_OPT, P_UNSET_EMPTY, null, null], 44 'filter_timetill' => [T_ZBX_STR, O_OPT, P_UNSET_EMPTY, null, null] 45]; 46check_fields($fields); 47 48$availabilityReportMode = getRequest('mode', CProfile::get('web.avail_report.mode', AVAILABILITY_REPORT_BY_HOST)); 49CProfile::update('web.avail_report.mode', $availabilityReportMode, PROFILE_TYPE_INT); 50 51/* 52 * Permissions 53 */ 54if ($availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 55 if (getRequest('hostgroupid') && !API::HostGroup()->isReadable([$_REQUEST['hostgroupid']]) 56 || getRequest('filter_groupid') && !API::HostGroup()->isReadable([$_REQUEST['filter_groupid']]) 57 || getRequest('filter_hostid') && !API::Host()->isReadable([$_REQUEST['filter_hostid']])) { 58 access_deny(); 59 } 60 if (getRequest('tpl_triggerid')) { 61 $trigger = API::Trigger()->get([ 62 'triggerids' => $_REQUEST['tpl_triggerid'], 63 'output' => ['triggerid'], 64 'filter' => ['flags' => null] 65 ]); 66 if (!$trigger) { 67 access_deny(); 68 } 69 } 70} 71else { 72 if (getRequest('filter_groupid') && !API::HostGroup()->isReadable([$_REQUEST['filter_groupid']]) 73 || getRequest('filter_hostid') && !API::Host()->isReadable([$_REQUEST['filter_hostid']])) { 74 access_deny(); 75 } 76} 77if (getRequest('triggerid') && !API::Trigger()->isReadable([$_REQUEST['triggerid']])) { 78 access_deny(); 79} 80 81/* 82 * Filter 83 */ 84if (hasRequest('filter_rst')) { 85 $_REQUEST['filter_groupid'] = 0; 86 $_REQUEST['filter_hostid'] = 0; 87 $_REQUEST['filter_timesince'] = 0; 88 $_REQUEST['filter_timetill'] = 0; 89 90 if ($availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 91 $_REQUEST['tpl_triggerid'] = 0; 92 $_REQUEST['hostgroupid'] = 0; 93 } 94} 95 96if (!hasRequest('filter_rst')) { 97 $_REQUEST['filter_groupid'] = getRequest('filter_groupid', 98 CProfile::get('web.avail_report.'.$availabilityReportMode.'.groupid', 0) 99 ); 100 $_REQUEST['filter_hostid'] = getRequest('filter_hostid', 101 CProfile::get('web.avail_report.'.$availabilityReportMode.'.hostid', 0) 102 ); 103 $_REQUEST['filter_timesince'] = getRequest('filter_timesince', 104 CProfile::get('web.avail_report.'.$availabilityReportMode.'.timesince', 0) 105 ); 106 $_REQUEST['filter_timetill'] = getRequest('filter_timetill', 107 CProfile::get('web.avail_report.'.$availabilityReportMode.'.timetill', 0) 108 ); 109 110 if ($availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 111 $_REQUEST['tpl_triggerid'] = getRequest('tpl_triggerid', 112 CProfile::get('web.avail_report.'.$availabilityReportMode.'.tpl_triggerid', 0) 113 ); 114 115 $_REQUEST['hostgroupid'] = getRequest('hostgroupid', 116 CProfile::get('web.avail_report.'.$availabilityReportMode.'.hostgroupid', 0) 117 ); 118 } 119} 120 121CProfile::update('web.avail_report.'.$availabilityReportMode.'.groupid', getRequest('filter_groupid', 0), 122 PROFILE_TYPE_ID 123); 124CProfile::update('web.avail_report.'.$availabilityReportMode.'.timesince', getRequest('filter_timesince', 0), 125 PROFILE_TYPE_STR 126); 127CProfile::update('web.avail_report.'.$availabilityReportMode.'.timetill', getRequest('filter_timetill', 0), 128 PROFILE_TYPE_STR 129); 130CProfile::update('web.avail_report.'.$availabilityReportMode.'.hostid', getRequest('filter_hostid', 0), 131 PROFILE_TYPE_ID 132); 133 134if ($availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 135 CProfile::update('web.avail_report.'.$availabilityReportMode.'.tpl_triggerid', getRequest('tpl_triggerid', 0), 136 PROFILE_TYPE_ID 137 ); 138 139 CProfile::update('web.avail_report.'.$availabilityReportMode.'.hostgroupid', getRequest('hostgroupid', 0), 140 PROFILE_TYPE_ID 141 ); 142} 143 144$config = select_config(); 145 146if ($_REQUEST['filter_timetill'] > 0 && $_REQUEST['filter_timesince'] > $_REQUEST['filter_timetill']) { 147 zbx_swap($_REQUEST['filter_timesince'], $_REQUEST['filter_timetill']); 148} 149 150$_REQUEST['filter_timesince'] = zbxDateToTime($_REQUEST['filter_timesince'] 151 ? $_REQUEST['filter_timesince'] : date(TIMESTAMP_FORMAT_ZERO_TIME, time() - SEC_PER_DAY)); 152$_REQUEST['filter_timetill'] = zbxDateToTime($_REQUEST['filter_timetill'] 153 ? $_REQUEST['filter_timetill'] : date(TIMESTAMP_FORMAT_ZERO_TIME, time())); 154 155/* 156 * Header 157 */ 158$triggerData = isset($_REQUEST['triggerid']) 159 ? API::Trigger()->get([ 160 'triggerids' => $_REQUEST['triggerid'], 161 'output' => API_OUTPUT_EXTEND, 162 'selectHosts' => API_OUTPUT_EXTEND, 163 'expandDescription' => true 164 ]) 165 : null; 166 167$reportWidget = (new CWidget())->setTitle(_('Availability report')); 168 169if ($triggerData) { 170 $triggerData = reset($triggerData); 171 $host = reset($triggerData['hosts']); 172 173 $triggerData['hostid'] = $host['hostid']; 174 $triggerData['hostname'] = $host['name']; 175 176 $reportWidget->setControls( 177 (new CList()) 178 ->addItem(new CLink($triggerData['hostname'], '?filter_groupid='.$_REQUEST['filter_groupid'])) 179 ->addItem($triggerData['description']) 180 ); 181 182 $table = (new CTableInfo()) 183 ->addRow(new CImg('chart4.php?triggerid='.$_REQUEST['triggerid'])); 184 185 $reportWidget->addItem(BR()) 186 ->addItem($table) 187 ->show(); 188} 189elseif (isset($_REQUEST['filter_hostid'])) { 190 $headerForm = (new CForm('get'))->addItem((new CList()) 191 ->addItem([ 192 new CLabel(_('Mode'), 'mode'), 193 (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), 194 new CComboBox('mode', $availabilityReportMode, 'submit()', [ 195 AVAILABILITY_REPORT_BY_HOST => _('By host'), 196 AVAILABILITY_REPORT_BY_TEMPLATE => _('By trigger template') 197 ]) 198 ]) 199 ); 200 $reportWidget->setControls($headerForm); 201 202 $triggerOptions = [ 203 'output' => ['triggerid', 'description', 'expression', 'value'], 204 'expandDescription' => true, 205 'monitored' => true, 206 'selectHosts' => ['name'], 207 'filter' => [], 208 'hostids' => null, 209 'limit' => $config['search_limit'] + 1 210 ]; 211 212 /* 213 * Filter 214 */ 215 $filterForm = (new CFilter('web.avail_report.filter.state')) 216 ->addVar('config', $availabilityReportMode) 217 ->addVar('filter_timesince', date(TIMESTAMP_FORMAT, $_REQUEST['filter_timesince'])) 218 ->addVar('filter_timetill', date(TIMESTAMP_FORMAT, $_REQUEST['filter_timetill'])); 219 220 $filterColumn1 = new CFormList(); 221 $filterColumn2 = new CFormList(); 222 223 // report by template 224 if ($availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 225 // trigger options 226 if (!empty($_REQUEST['filter_hostid'])) { 227 $hosts = API::Host()->get([ 228 'output' => ['hostid'], 229 'templateids' => $_REQUEST['filter_hostid'] 230 ]); 231 232 $triggerOptions['hostids'] = zbx_objectValues($hosts, 'hostid'); 233 } 234 if (isset($_REQUEST['tpl_triggerid']) && !empty($_REQUEST['tpl_triggerid'])) { 235 $triggerOptions['filter']['templateid'] = $_REQUEST['tpl_triggerid']; 236 } 237 if (isset($_REQUEST['hostgroupid']) && !empty($_REQUEST['hostgroupid'])) { 238 $triggerOptions['groupids'] = $_REQUEST['hostgroupid']; 239 } 240 241 // filter template group 242 $groupsComboBox = new CComboBox('filter_groupid', $_REQUEST['filter_groupid'], 'javascript: submit();'); 243 $groupsComboBox->addItem(0, _('all')); 244 245 $groups = API::HostGroup()->get([ 246 'output' => ['groupid', 'name'], 247 'templated_hosts' => true, 248 'with_triggers' => true 249 ]); 250 order_result($groups, 'name'); 251 252 foreach ($groups as $group) { 253 $groupsComboBox->addItem($group['groupid'], $group['name']); 254 } 255 $filterColumn1->addRow(_('Template group'), $groupsComboBox); 256 257 // filter template 258 $templateComboBox = new CComboBox('filter_hostid', $_REQUEST['filter_hostid'], 'javascript: submit();'); 259 $templateComboBox->addItem(0, _('all')); 260 261 $templates = API::Template()->get([ 262 'output' => ['templateid', 'name'], 263 'groupids' => empty($_REQUEST['filter_groupid']) ? null : $_REQUEST['filter_groupid'], 264 'with_triggers' => true 265 ]); 266 order_result($templates, 'name'); 267 268 $templateIds = []; 269 foreach ($templates as $template) { 270 $templateIds[$template['templateid']] = $template['templateid']; 271 272 $templateComboBox->addItem($template['templateid'], $template['name']); 273 } 274 $filterColumn1->addRow(_('Template'), $templateComboBox); 275 276 // filter trigger 277 $triggerComboBox = new CComboBox('tpl_triggerid', getRequest('tpl_triggerid', 0), 'javascript: submit()'); 278 $triggerComboBox->addItem(0, _('all')); 279 280 $sqlCondition = empty($_REQUEST['filter_hostid']) 281 ? ' AND '.dbConditionInt('h.hostid', $templateIds) 282 : ' AND h.hostid='.zbx_dbstr($_REQUEST['filter_hostid']); 283 284 $sql = 285 'SELECT DISTINCT t.triggerid,t.description,h.name'. 286 ' FROM triggers t,hosts h,items i,functions f'. 287 ' WHERE f.itemid=i.itemid'. 288 ' AND h.hostid=i.hostid'. 289 ' AND t.status='.TRIGGER_STATUS_ENABLED. 290 ' AND t.triggerid=f.triggerid'. 291 ' AND h.status='.HOST_STATUS_TEMPLATE. 292 ' AND i.status='.ITEM_STATUS_ACTIVE. 293 $sqlCondition. 294 ' ORDER BY t.description'; 295 $triggers = DBfetchArrayAssoc(DBselect($sql), 'triggerid'); 296 297 foreach ($triggers as $trigger) { 298 $templateName = empty($_REQUEST['filter_hostid']) ? $trigger['name'].NAME_DELIMITER : ''; 299 300 $triggerComboBox->addItem($trigger['triggerid'], $templateName.$trigger['description']); 301 } 302 303 if (isset($_REQUEST['tpl_triggerid']) && !isset($triggers[$_REQUEST['tpl_triggerid']])) { 304 unset($triggerOptions['filter']['templateid']); 305 } 306 307 $filterColumn1->addRow(_('Template trigger'), $triggerComboBox); 308 309 // filter host group 310 $hostGroupsComboBox = new CComboBox('hostgroupid', getRequest('hostgroupid', 0), 'javascript: submit()'); 311 $hostGroupsComboBox->addItem(0, _('all')); 312 313 $hostGroups = API::HostGroup()->get([ 314 'output' => ['groupid', 'name'], 315 'hostids' => $triggerOptions['hostids'], 316 'monitored_hosts' => true, 317 'preservekeys' => true 318 ]); 319 order_result($hostGroups, 'name'); 320 321 foreach ($hostGroups as $hostGroup) { 322 $hostGroupsComboBox->addItem($hostGroup['groupid'], $hostGroup['name']); 323 } 324 325 if (isset($_REQUEST['hostgroupid']) && !isset($hostGroups[$_REQUEST['hostgroupid']])) { 326 unset($triggerOptions['groupids']); 327 } 328 329 $filterColumn1->addRow(_('Filter by host group'), $hostGroupsComboBox); 330 } 331 332 // report by host 333 elseif ($availabilityReportMode == AVAILABILITY_REPORT_BY_HOST) { 334 // filter host group 335 $groupsComboBox = new CComboBox('filter_groupid', $_REQUEST['filter_groupid'], 'javascript: submit();'); 336 $groupsComboBox->addItem(0, _('all')); 337 338 $groups = API::HostGroup()->get([ 339 'output' => ['groupid', 'name'], 340 'monitored_hosts' => true, 341 'with_triggers' => true 342 ]); 343 order_result($groups, 'name'); 344 345 foreach ($groups as $group) { 346 $groupsComboBox->addItem($group['groupid'], $group['name']); 347 } 348 $filterColumn1->addRow(_('Host group'), $groupsComboBox); 349 350 // filter host 351 $hostsComboBox = new CComboBox('filter_hostid', $_REQUEST['filter_hostid'], 'javascript: submit();'); 352 $hostsComboBox->addItem(0, _('all')); 353 354 $hosts = API::Host()->get([ 355 'groupids' => empty($_REQUEST['filter_groupid']) ? null : $_REQUEST['filter_groupid'], 356 'output' => ['hostid', 'name'], 357 'monitored_hosts' => true, 358 'with_triggers' => true 359 ]); 360 order_result($hosts, 'name'); 361 $hosts = zbx_toHash($hosts, 'hostid'); 362 363 foreach ($hosts as $host) { 364 $hostsComboBox->addItem($host['hostid'], $host['name']); 365 } 366 $filterColumn1->addRow(_('Host'), $hostsComboBox); 367 368 // trigger options 369 if (!empty($_REQUEST['filter_groupid'])) { 370 $triggerOptions['groupids'] = $_REQUEST['filter_groupid']; 371 } 372 if (!empty($_REQUEST['filter_hostid']) && isset($hosts[$_REQUEST['filter_hostid']])) { 373 $triggerOptions['hostids'] = $_REQUEST['filter_hostid']; 374 } 375 } 376 377 // filter period 378 $filterColumn2->addRow(_('From'), createDateSelector('filter_timesince', $_REQUEST['filter_timesince'], 'filter_timetill')); 379 $filterColumn2->addRow(_('To'), createDateSelector('filter_timetill', $_REQUEST['filter_timetill'], 'filter_timesince')); 380 381 $filterForm->addColumn($filterColumn1); 382 $filterForm->addColumn($filterColumn2); 383 384 $reportWidget->addItem($filterForm); 385 386 /* 387 * Triggers 388 */ 389 $triggerTable = (new CTableInfo()) 390 ->setHeader([ 391 ($_REQUEST['filter_hostid'] == 0 || $availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) ? _('Host') : null, 392 _('Name'), 393 _('Problems'), 394 _('Ok'), 395 _('Graph') 396 ]); 397 398 $triggers = API::Trigger()->get($triggerOptions); 399 400 if (getRequest('filter_hostid') == 0 || $availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) { 401 foreach ($triggers as &$trigger) { 402 $trigger['host_name'] = $trigger['hosts'][0]['name']; 403 } 404 unset($trigger); 405 406 CArrayHelper::sort($triggers, ['host_name', 'description']); 407 } 408 else { 409 CArrayHelper::sort($triggers, ['description']); 410 } 411 412 $paging = getPagingLine($triggers, ZBX_SORT_UP, new CUrl('report2.php')); 413 414 foreach ($triggers as $trigger) { 415 $availability = calculateAvailability($trigger['triggerid'], getRequest('filter_timesince'), 416 getRequest('filter_timetill') 417 ); 418 419 $triggerTable->addRow([ 420 ($_REQUEST['filter_hostid'] == 0 || $availabilityReportMode == AVAILABILITY_REPORT_BY_TEMPLATE) 421 ? $trigger['host_name'] : null, 422 new CLink($trigger['description'], 'events.php?filter_set=1&triggerid='.$trigger['triggerid']), 423 $availability['true'] < 0.00005 424 ? '' 425 : (new CSpan(sprintf('%.4f%%', $availability['true'])))->addClass(ZBX_STYLE_RED), 426 $availability['false'] < 0.00005 427 ? '' 428 : (new CSpan(sprintf('%.4f%%', $availability['false'])))->addClass(ZBX_STYLE_GREEN), 429 new CLink(_('Show'), 'report2.php?filter_groupid='.$_REQUEST['filter_groupid']. 430 '&filter_hostid='.$_REQUEST['filter_hostid'].'&triggerid='.$trigger['triggerid']) 431 ]); 432 } 433 434 $reportWidget->addItem([$triggerTable, $paging]) 435 ->show(); 436} 437 438require_once dirname(__FILE__).'/include/page_footer.php'; 439