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/** 23 * A class to display discovery table as a screen element. 24 */ 25class CScreenDiscovery extends CScreenBase { 26 27 /** 28 * Data 29 * 30 * @var array 31 */ 32 protected $data = []; 33 34 /** 35 * Init screen data. 36 * 37 * @param array $options 38 * @param array $options['data'] 39 */ 40 public function __construct(array $options = []) { 41 parent::__construct($options); 42 43 $this->data = $options['data']; 44 } 45 46 /** 47 * Process screen. 48 * 49 * @return CDiv (screen inside container) 50 */ 51 public function get() { 52 $this->dataId = 'discovery'; 53 54 $sort_field = $this->data['sort']; 55 $sort_order = $this->data['sortorder']; 56 $druleid = $this->data['druleid']; 57 58 // discovery rules 59 $options = [ 60 'output' => ['druleid', 'name'], 61 'selectDHosts' => ['dhostid', 'status', 'lastup', 'lastdown'], 62 'filter' => ['status' => DRULE_STATUS_ACTIVE] 63 ]; 64 65 if ($druleid > 0) { 66 $options['druleids'] = $druleid; // set selected discovery rule id 67 } 68 69 $drules = API::DRule()->get($options); 70 if ($drules) { 71 order_result($drules, 'name'); 72 } 73 74 // discovery services 75 $options = [ 76 'selectHosts' => ['hostid', 'name', 'status'], 77 'output' => ['dserviceid', 'type', 'key_', 'port', 'status', 'lastup', 'lastdown', 'ip', 'dns'], 78 'sortfield' => $sort_field, 79 'sortorder' => $sort_order, 80 'limitSelects' => 1 81 ]; 82 if ($druleid > 0) { 83 $options['druleids'] = $druleid; 84 } 85 else { 86 $options['druleids'] = zbx_objectValues($drules, 'druleid'); 87 } 88 $dservices = API::DService()->get($options); 89 90 // user macros 91 $macros = API::UserMacro()->get([ 92 'output' => ['macro', 'value'], 93 'globalmacro' => true 94 ]); 95 $macros = zbx_toHash($macros, 'macro'); 96 97 // services 98 $services = []; 99 foreach ($dservices as $dservice) { 100 $key_ = $dservice['key_']; 101 if ($key_ !== '') { 102 if (array_key_exists($key_, $macros)) { 103 $key_ = $macros[$key_]['value']; 104 } 105 $key_ = ': '.$key_; 106 } 107 $service_name = discovery_check_type2str($dservice['type']). 108 discovery_port2str($dservice['type'], $dservice['port']).$key_; 109 $services[$service_name] = 1; 110 } 111 ksort($services); 112 113 // discovery services to hash 114 $dservices = zbx_toHash($dservices, 'dserviceid'); 115 116 // discovery hosts 117 $dhosts = API::DHost()->get([ 118 'druleids' => zbx_objectValues($drules, 'druleid'), 119 'selectDServices' => ['dserviceid', 'ip', 'dns', 'type', 'status', 'key_'], 120 'output' => ['dhostid', 'lastdown', 'lastup', 'druleid'] 121 ]); 122 $dhosts = zbx_toHash($dhosts, 'dhostid'); 123 124 $header = [ 125 make_sorting_header(_('Discovered device'), 'ip', $sort_field, $sort_order, 126 'zabbix.php?action=discovery.view' 127 ), 128 _('Monitored host'), 129 _('Uptime').'/'._('Downtime') 130 ]; 131 132 foreach ($services as $name => $foo) { 133 $header[] = (new CColHeader($name))->addClass('vertical_rotation'); 134 } 135 136 // create table 137 $table = (new CTableInfo()) 138 ->makeVerticalRotation() 139 ->setHeader($header); 140 141 foreach ($drules as $drule) { 142 $discovery_info = []; 143 144 foreach ($drule['dhosts'] as $dhost) { 145 if ($dhost['status'] == DHOST_STATUS_DISABLED) { 146 $hclass = 'disabled'; 147 $htime = $dhost['lastdown']; 148 } 149 else { 150 $hclass = 'enabled'; 151 $htime = $dhost['lastup']; 152 } 153 154 // $primary_ip stores the primary host ip of the dhost 155 $primary_ip = ''; 156 157 foreach ($dhosts[$dhost['dhostid']]['dservices'] as $dservice) { 158 $dservice = $dservices[$dservice['dserviceid']]; 159 160 $hostName = ''; 161 162 $host = reset($dservices[$dservice['dserviceid']]['hosts']); 163 if (!is_null($host)) { 164 $hostName = $host['name']; 165 } 166 167 if ($primary_ip !== '') { 168 if ($primary_ip === $dservice['ip']) { 169 $htype = 'primary'; 170 } 171 else { 172 $htype = 'slave'; 173 } 174 } 175 else { 176 $primary_ip = $dservice['ip']; 177 $htype = 'primary'; 178 } 179 180 if (!array_key_exists($dservice['ip'], $discovery_info)) { 181 $discovery_info[$dservice['ip']] = [ 182 'ip' => $dservice['ip'], 183 'dns' => $dservice['dns'], 184 'type' => $htype, 185 'class' => $hclass, 186 'host' => $hostName, 187 'time' => $htime, 188 ]; 189 } 190 191 if ($dservice['status'] == DSVC_STATUS_DISABLED) { 192 $class = ZBX_STYLE_INACTIVE_BG; 193 $time = 'lastdown'; 194 } 195 else { 196 $class = ZBX_STYLE_ACTIVE_BG; 197 $time = 'lastup'; 198 } 199 200 $key_ = $dservice['key_']; 201 if ($key_ !== '') { 202 if (array_key_exists($key_, $macros)) { 203 $key_ = $macros[$key_]['value']; 204 } 205 $key_ = NAME_DELIMITER.$key_; 206 } 207 208 $service_name = discovery_check_type2str($dservice['type']). 209 discovery_port2str($dservice['type'], $dservice['port']).$key_; 210 211 $discovery_info[$dservice['ip']]['services'][$service_name] = [ 212 'class' => $class, 213 'time' => $dservice[$time] 214 ]; 215 } 216 } 217 218 if ($druleid == 0 && $discovery_info) { 219 $col = new CCol( 220 [bold($drule['name']), SPACE.'('._n('%d device', '%d devices', count($discovery_info)).')'] 221 ); 222 $col->setColSpan(count($services) + 3); 223 224 $table->addRow($col); 225 } 226 order_result($discovery_info, $sort_field, $sort_order); 227 228 foreach ($discovery_info as $ip => $h_data) { 229 $dns = $h_data['dns'] == '' ? '' : ' ('.$h_data['dns'].')'; 230 $row = [ 231 $h_data['type'] == 'primary' 232 ? (new CSpan($ip.$dns))->addClass($h_data['class']) 233 : new CSpan(SPACE.SPACE.$ip.$dns), 234 new CSpan(array_key_exists('host', $h_data) ? $h_data['host'] : ''), 235 (new CSpan((($h_data['time'] == 0 || $h_data['type'] === 'slave') 236 ? '' 237 : convert_units(['value' => time() - $h_data['time'], 'units' => 'uptime']))) 238 ) 239 ->addClass($h_data['class']) 240 ]; 241 242 foreach ($services as $name => $foo) { 243 $class = null; 244 $time = SPACE; 245 $hint = (new CDiv(SPACE))->addClass($class); 246 247 $hint_table = null; 248 if (array_key_exists($name, $h_data['services'])) { 249 $class = $h_data['services'][$name]['class']; 250 $time = $h_data['services'][$name]['time']; 251 252 $hint_table = (new CTableInfo())->setAttribute('style', 'width: auto;'); 253 254 if ($class == ZBX_STYLE_ACTIVE_BG) { 255 $hint_table->setHeader(_('Uptime')); 256 } 257 else { 258 $hint_table->setHeader(_('Downtime')); 259 } 260 261 $hint_table->addRow( 262 (new CCol(zbx_date2age($h_data['services'][$name]['time'])))->addClass($class) 263 ); 264 } 265 $column = (new CCol($hint))->addClass($class); 266 if (!is_null($hint_table)) { 267 $column->setHint($hint_table); 268 } 269 $row[] = $column; 270 } 271 $table->addRow($row); 272 } 273 } 274 275 return $this->getOutput($table, true, $this->data); 276 } 277} 278