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/items.inc.php';
24
25$page['title'] = _('Queue');
26$page['file'] = 'queue.php';
27
28define('ZBX_PAGE_DO_REFRESH', 1);
29
30require_once dirname(__FILE__).'/include/page_header.php';
31
32$queueModes = [
33	QUEUE_OVERVIEW,
34	QUEUE_OVERVIEW_BY_PROXY,
35	QUEUE_DETAILS
36];
37
38//		VAR			TYPE	OPTIONAL FLAGS	VALIDATION	EXCEPTION
39$fields = [
40	'config' => [T_ZBX_INT, O_OPT, P_SYS, IN($queueModes), null]
41];
42
43check_fields($fields);
44
45$config = getRequest('config', CProfile::get('web.queue.config', 0));
46CProfile::update('web.queue.config', $config, PROFILE_TYPE_INT);
47
48// fetch data
49$zabbixServer = new CZabbixServer($ZBX_SERVER, $ZBX_SERVER_PORT, ZBX_SOCKET_TIMEOUT, ZBX_SOCKET_BYTES_LIMIT);
50$queueRequests = [
51	QUEUE_OVERVIEW => CZabbixServer::QUEUE_OVERVIEW,
52	QUEUE_OVERVIEW_BY_PROXY => CZabbixServer::QUEUE_OVERVIEW_BY_PROXY,
53	QUEUE_DETAILS => CZabbixServer::QUEUE_DETAILS
54];
55$queueData = $zabbixServer->getQueue($queueRequests[$config], get_cookie('zbx_sessionid'), QUEUE_DETAIL_ITEM_COUNT);
56
57// check for errors error
58if ($zabbixServer->getError()) {
59	error($zabbixServer->getError());
60	show_error_message(_('Cannot display item queue.'));
61
62	require_once dirname(__FILE__).'/include/page_footer.php';
63}
64
65$widget = (new CWidget())
66	->setTitle(_('Queue of items to be updated'))
67	->setControls((new CForm('get'))
68		->cleanItems()
69		->addItem((new CList())
70			->addItem((new CComboBox('config', $config, 'submit();', [
71				QUEUE_OVERVIEW => _('Overview'),
72				QUEUE_OVERVIEW_BY_PROXY => _('Overview by proxy'),
73				QUEUE_DETAILS => _('Details')
74			])))
75		)
76	);
77
78$table = new CTableInfo();
79
80$severityConfig = select_config();
81
82// overview
83if ($config == QUEUE_OVERVIEW) {
84	$itemTypes = [
85		ITEM_TYPE_ZABBIX,
86		ITEM_TYPE_ZABBIX_ACTIVE,
87		ITEM_TYPE_SIMPLE,
88		ITEM_TYPE_SNMPV1,
89		ITEM_TYPE_SNMPV2C,
90		ITEM_TYPE_SNMPV3,
91		ITEM_TYPE_INTERNAL,
92		ITEM_TYPE_AGGREGATE,
93		ITEM_TYPE_EXTERNAL,
94		ITEM_TYPE_DB_MONITOR,
95		ITEM_TYPE_IPMI,
96		ITEM_TYPE_SSH,
97		ITEM_TYPE_TELNET,
98		ITEM_TYPE_JMX,
99		ITEM_TYPE_CALCULATED
100	];
101
102	$table->setHeader([
103		_('Items'),
104		_('5 seconds'),
105		_('10 seconds'),
106		_('30 seconds'),
107		_('1 minute'),
108		_('5 minutes'),
109		_('More than 10 minutes')
110	]);
111
112	$queueData = zbx_toHash($queueData, 'itemtype');
113
114	foreach ($itemTypes as $type) {
115		if (isset($queueData[$type])) {
116			$itemTypeData = $queueData[$type];
117		}
118		else {
119			$itemTypeData = [
120				'delay5' => 0,
121				'delay10' => 0,
122				'delay30' => 0,
123				'delay60' => 0,
124				'delay300' => 0,
125				'delay600' => 0
126			];
127		}
128
129		$table->addRow([
130			item_type2str($type),
131			getSeverityCell(TRIGGER_SEVERITY_NOT_CLASSIFIED, $severityConfig, $itemTypeData['delay5'],
132				!$itemTypeData['delay5']
133			),
134			getSeverityCell(TRIGGER_SEVERITY_INFORMATION, $severityConfig, $itemTypeData['delay10'],
135				!$itemTypeData['delay10']
136			),
137			getSeverityCell(TRIGGER_SEVERITY_WARNING, $severityConfig, $itemTypeData['delay30'],
138				!$itemTypeData['delay30']
139			),
140			getSeverityCell(TRIGGER_SEVERITY_AVERAGE, $severityConfig, $itemTypeData['delay60'],
141				!$itemTypeData['delay60']
142			),
143			getSeverityCell(TRIGGER_SEVERITY_HIGH, $severityConfig, $itemTypeData['delay300'],
144				!$itemTypeData['delay300']
145			),
146			getSeverityCell(TRIGGER_SEVERITY_DISASTER, $severityConfig, $itemTypeData['delay600'],
147				!$itemTypeData['delay600']
148			)
149		]);
150	}
151}
152
153// overview by proxy
154elseif ($config == QUEUE_OVERVIEW_BY_PROXY) {
155	$proxies = API::proxy()->get([
156		'output' => ['hostid', 'host'],
157		'preservekeys' => true
158	]);
159	order_result($proxies, 'host');
160
161	$proxies[0] = ['host' => _('Server')];
162
163	$table->setHeader([
164		_('Proxy'),
165		_('5 seconds'),
166		_('10 seconds'),
167		_('30 seconds'),
168		_('1 minute'),
169		_('5 minutes'),
170		_('More than 10 minutes')
171	]);
172
173	$queueData = zbx_toHash($queueData, 'proxyid');
174	foreach ($proxies as $proxyId => $proxy) {
175		if (isset($queueData[$proxyId])) {
176			$proxyData = $queueData[$proxyId];
177		}
178		else {
179			$proxyData = [
180				'delay5' => 0,
181				'delay10' => 0,
182				'delay30' => 0,
183				'delay60' => 0,
184				'delay300' => 0,
185				'delay600' => 0
186			];
187		}
188
189		$table->addRow([
190			$proxy['host'],
191			getSeverityCell(TRIGGER_SEVERITY_NOT_CLASSIFIED, $severityConfig, $proxyData['delay5'],
192				!$proxyData['delay5']
193			),
194			getSeverityCell(TRIGGER_SEVERITY_INFORMATION, $severityConfig, $proxyData['delay10'],
195				!$proxyData['delay10']
196			),
197			getSeverityCell(TRIGGER_SEVERITY_WARNING, $severityConfig, $proxyData['delay30'], !$proxyData['delay30']),
198			getSeverityCell(TRIGGER_SEVERITY_AVERAGE, $severityConfig, $proxyData['delay60'], !$proxyData['delay60']),
199			getSeverityCell(TRIGGER_SEVERITY_HIGH, $severityConfig, $proxyData['delay300'], !$proxyData['delay300']),
200			getSeverityCell(TRIGGER_SEVERITY_DISASTER, $severityConfig, $proxyData['delay600'], !$proxyData['delay600'])
201		]);
202	}
203}
204
205// details
206elseif ($config == QUEUE_DETAILS) {
207	$queueData = zbx_toHash($queueData, 'itemid');
208
209	$items = API::Item()->get([
210		'output' => ['itemid', 'hostid', 'name', 'key_'],
211		'selectHosts' => ['name'],
212		'itemids' => array_keys($queueData),
213		'webitems' => true,
214		'preservekeys' => true
215	]);
216
217	$items = CMacrosResolverHelper::resolveItemNames($items);
218
219	// get hosts for queue items
220	$hostIds = zbx_objectValues($items, 'hostid');
221	$hostIds = array_keys(array_flip($hostIds));
222
223	$hosts = API::Host()->get([
224		'output' => ['hostid', 'proxy_hostid'],
225		'hostids' => $hostIds,
226		'preservekeys' => true
227	]);
228
229	// get proxies for those hosts
230	$proxyHostIds = [];
231	foreach ($hosts as $host) {
232		if ($host['proxy_hostid']) {
233			$proxyHostIds[$host['proxy_hostid']] = $host['proxy_hostid'];
234		}
235	}
236
237	if ($proxyHostIds) {
238		$proxies = API::Proxy()->get([
239			'proxyids' => $proxyHostIds,
240			'output' => ['proxyid', 'host'],
241			'preservekeys' => true
242		]);
243	}
244
245	$table->setHeader([
246		_('Scheduled check'),
247		_('Delayed by'),
248		_('Host'),
249		_('Name')
250	]);
251
252	$i = 0;
253	foreach ($queueData as $itemData) {
254		if (!isset($items[$itemData['itemid']])) {
255			continue;
256		}
257
258		// display only the first QUEUE_DETAIL_ITEM_COUNT items (can only occur when using old server versions)
259		$i++;
260		if ($i > QUEUE_DETAIL_ITEM_COUNT) {
261			break;
262		}
263
264		$item = $items[$itemData['itemid']];
265		$host = reset($item['hosts']);
266
267		$table->addRow([
268			zbx_date2str(DATE_TIME_FORMAT_SECONDS, $itemData['nextcheck']),
269			zbx_date2age($itemData['nextcheck']),
270			(isset($proxies[$hosts[$item['hostid']]['proxy_hostid']]))
271				? $proxies[$hosts[$item['hostid']]['proxy_hostid']]['host'].NAME_DELIMITER.$host['name']
272				: $host['name'],
273			$item['name_expanded']
274		]);
275	}
276}
277
278// display the table footer
279if ($config == QUEUE_OVERVIEW_BY_PROXY) {
280	$total = _('Total').': '.$table->getNumRows();
281}
282elseif ($config == QUEUE_DETAILS) {
283	if (null !== $zabbixServer->getTotalCount()) {
284		$total = _s('Displaying %1$s of %2$s found', $table->getNumRows(), $zabbixServer->getTotalCount());
285	}
286	else {
287		// fallback to old solution
288		$total = _('Total').': '.$table->getNumRows().
289			(count($queueData) > QUEUE_DETAIL_ITEM_COUNT ? ' ('._('Truncated').')' : '');
290	}
291}
292else {
293	$total = null;
294}
295
296if ($total !== null) {
297	$total = (new CDiv())
298		->addClass(ZBX_STYLE_TABLE_PAGING)
299		->addItem((new CDiv())
300			->addClass(ZBX_STYLE_PAGING_BTN_CONTAINER)
301			->addItem((new CDiv())
302				->addClass(ZBX_STYLE_TABLE_STATS)
303				->addItem($total)
304			)
305		);
306}
307
308$widget
309	->addItem($table)
310	->addItem($total)
311	->show();
312
313require_once dirname(__FILE__).'/include/page_footer.php';
314