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
57		$drules = API::DRule()->get([
58			'output' => ['druleid', 'name'],
59			'selectDHosts' => ['dhostid', 'status', 'lastup', 'lastdown'],
60			'druleids' => (array_key_exists('filter_druleids', $this->data) && $this->data['filter_druleids'])
61				? $this->data['filter_druleids']
62				: null,
63			'filter' => ['status' => DRULE_STATUS_ACTIVE],
64			'preservekeys' => true
65		]);
66
67		order_result($drules, 'name');
68
69		$dservices = API::DService()->get([
70			'output' => ['dserviceid', 'port', 'status', 'lastup', 'lastdown', 'dcheckid', 'ip', 'dns'],
71			'selectHosts' => ['hostid', 'name', 'status'],
72			'druleids' => array_keys($drules),
73			'sortfield' => $sort_field,
74			'sortorder' => $sort_order,
75			'limitSelects' => 1,
76			'preservekeys' => true
77		]);
78
79		// user macros
80		$macros = API::UserMacro()->get([
81			'output' => ['macro', 'value', 'type'],
82			'globalmacro' => true
83		]);
84		$macros = zbx_toHash($macros, 'macro');
85
86		$dchecks = API::DCheck()->get([
87			'output' => ['type', 'key_'],
88			'dserviceids' => array_keys($dservices),
89			'preservekeys' => true
90		]);
91
92		// services
93		$services = [];
94		foreach ($dservices as $dservice) {
95			$key_ = $dchecks[$dservice['dcheckid']]['key_'];
96			if ($key_ !== '') {
97				if (array_key_exists($key_, $macros)) {
98					$key_ = CMacrosResolverGeneral::getMacroValue($macros[$key_]);
99				}
100				$key_ = ': '.$key_;
101			}
102			$service_name = discovery_check_type2str($dchecks[$dservice['dcheckid']]['type']).
103				discovery_port2str($dchecks[$dservice['dcheckid']]['type'], $dservice['port']).$key_;
104			$services[$service_name] = 1;
105		}
106		ksort($services);
107
108		$dhosts = API::DHost()->get([
109			'output' => ['dhostid'],
110			'selectDServices' => ['dserviceid'],
111			'druleids' => array_keys($drules),
112			'preservekeys' => true
113		]);
114
115		$header = [
116			make_sorting_header(_('Discovered device'), 'ip', $sort_field, $sort_order,
117				'zabbix.php?action=discovery.view'
118			),
119			_('Monitored host'),
120			_('Uptime').'/'._('Downtime')
121		];
122
123		foreach ($services as $name => $foo) {
124			$header[] = (new CColHeader($name))
125				->addClass('vertical_rotation')
126				->setTitle($name);
127		}
128
129		// create table
130		$table = (new CTableInfo())
131			->makeVerticalRotation()
132			->setHeader($header);
133
134		foreach ($drules as $drule) {
135			$discovery_info = [];
136
137			foreach ($drule['dhosts'] as $dhost) {
138				if ($dhost['status'] == DHOST_STATUS_DISABLED) {
139					$hclass = 'disabled';
140					$htime = $dhost['lastdown'];
141				}
142				else {
143					$hclass = 'enabled';
144					$htime = $dhost['lastup'];
145				}
146
147				// $primary_ip stores the primary host ip of the dhost
148				$primary_ip = '';
149
150				foreach ($dhosts[$dhost['dhostid']]['dservices'] as $dservice) {
151					$dservice = $dservices[$dservice['dserviceid']];
152
153					$hostName = '';
154
155					$host = reset($dservices[$dservice['dserviceid']]['hosts']);
156					if ($host) {
157						$hostName = $host['name'];
158					}
159
160					if ($primary_ip !== '') {
161						if ($primary_ip === $dservice['ip']) {
162							$htype = 'primary';
163						}
164						else {
165							$htype = 'slave';
166						}
167					}
168					else {
169						$primary_ip = $dservice['ip'];
170						$htype = 'primary';
171					}
172
173					if (!array_key_exists($dservice['ip'], $discovery_info)) {
174						$discovery_info[$dservice['ip']] = [
175							'ip' => $dservice['ip'],
176							'dns' => $dservice['dns'],
177							'type' => $htype,
178							'class' => $hclass,
179							'host' => $hostName,
180							'time' => $htime
181						];
182					}
183
184					if ($dservice['status'] == DSVC_STATUS_DISABLED) {
185						$class = ZBX_STYLE_INACTIVE_BG;
186						$time = 'lastdown';
187					}
188					else {
189						$class = null;
190						$time = 'lastup';
191					}
192
193					$key_ = $dchecks[$dservice['dcheckid']]['key_'];
194					if ($key_ !== '') {
195						if (array_key_exists($key_, $macros)) {
196							$key_ = CMacrosResolverGeneral::getMacroValue($macros[$key_]);
197						}
198						$key_ = NAME_DELIMITER.$key_;
199					}
200
201					$service_name = discovery_check_type2str($dchecks[$dservice['dcheckid']]['type']).
202						discovery_port2str($dchecks[$dservice['dcheckid']]['type'], $dservice['port']).$key_;
203
204					$discovery_info[$dservice['ip']]['services'][$service_name] = [
205						'class' => $class,
206						'time' => $dservice[$time]
207					];
208				}
209			}
210
211			if ($discovery_info) {
212				$col = new CCol(
213					[bold($drule['name']), SPACE.'('._n('%d device', '%d devices', count($discovery_info)).')']
214				);
215				$col->setColSpan(count($services) + 3);
216
217				$table->addRow($col);
218			}
219			order_result($discovery_info, $sort_field, $sort_order);
220
221			foreach ($discovery_info as $ip => $h_data) {
222				$dns = ($h_data['dns'] === '') ? '' : ' ('.$h_data['dns'].')';
223				$row = [
224					($h_data['type'] === 'primary')
225						? (new CSpan($ip.$dns))->addClass($h_data['class'])
226						: new CSpan(SPACE.SPACE.$ip.$dns),
227					new CSpan(array_key_exists('host', $h_data) ? $h_data['host'] : ''),
228					(new CSpan((($h_data['time'] == 0 || $h_data['type'] === 'slave')
229						? ''
230						: convertUnits(['value' => time() - $h_data['time'], 'units' => 'uptime'])))
231					)
232						->addClass($h_data['class'])
233				];
234
235				foreach ($services as $name => $foo) {
236					$row[] = array_key_exists($name, $h_data['services'])
237						? (new CCol(zbx_date2age($h_data['services'][$name]['time'])))
238							->addClass($h_data['services'][$name]['class'])
239						: '';
240				}
241				$table->addRow($row);
242			}
243		}
244
245		return $this->getOutput($table, true, $this->data);
246	}
247}
248