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'; 24require_once dirname(__FILE__).'/include/items.inc.php'; 25require_once dirname(__FILE__).'/include/forms.inc.php'; 26 27$page['title'] = _('Configuration of discovery rules'); 28$page['file'] = 'host_discovery.php'; 29$page['scripts'] = ['class.cviewswitcher.js', 'multilineinput.js', 'multiselect.js', 'items.js', 'textareaflexible.js', 30 'class.tab-indicators.js' 31]; 32 33require_once dirname(__FILE__).'/include/page_header.php'; 34 35$paramsFieldName = getParamFieldNameByType(getRequest('type', 0)); 36 37// supported eval types 38$evalTypes = [ 39 CONDITION_EVAL_TYPE_AND_OR, 40 CONDITION_EVAL_TYPE_AND, 41 CONDITION_EVAL_TYPE_OR, 42 CONDITION_EVAL_TYPE_EXPRESSION 43]; 44 45// VAR TYPE OPTIONAL FLAGS VALIDATION EXCEPTION 46$fields = [ 47 'hostid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, 'isset({form}) && !isset({itemid})'], 48 'itemid' => [T_ZBX_INT, O_NO, P_SYS, DB_ID, '(isset({form}) && ({form} == "update"))'], 49 'interfaceid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null, _('Interface')], 50 'name' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', _('Name')], 51 'description' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 52 'key' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', _('Key')], 53 'master_itemid' => [T_ZBX_STR, O_OPT, null, null, 54 '(isset({add}) || isset({update})) && isset({type})'. 55 ' && {type} == '.ITEM_TYPE_DEPENDENT, 56 _('Master item') 57 ], 58 'delay' => [T_ZBX_TU, O_OPT, P_ALLOW_USER_MACRO, null, 59 '(isset({add}) || isset({update})) && isset({type})'. 60 ' && {type} != '.ITEM_TYPE_TRAPPER.' && {type} != '.ITEM_TYPE_SNMPTRAP. 61 ' && {type} != '.ITEM_TYPE_DEPENDENT. 62 ' && !({type} == '.ITEM_TYPE_ZABBIX_ACTIVE. 63 ' && isset({key}) && strncmp({key}, "mqtt.get", 8) === 0)', 64 _('Update interval') 65 ], 66 'delay_flex' => [T_ZBX_STR, O_OPT, null, null, null], 67 'status' => [T_ZBX_INT, O_OPT, null, IN(ITEM_STATUS_ACTIVE), null], 68 'type' => [T_ZBX_INT, O_OPT, null, 69 IN([-1, ITEM_TYPE_ZABBIX, ITEM_TYPE_TRAPPER, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, 70 ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, 71 ITEM_TYPE_IPMI, ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX, 72 ITEM_TYPE_DEPENDENT, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 73 ]), 74 'isset({add}) || isset({update})' 75 ], 76 'authtype' => [T_ZBX_INT, O_OPT, null, IN(ITEM_AUTHTYPE_PASSWORD.','.ITEM_AUTHTYPE_PUBLICKEY), 77 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_SSH], 78 'username' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 79 '(isset({add}) || isset({update})) && isset({type})'. 80 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type'), 81 _('User name') 82 ], 83 'password' => [T_ZBX_STR, O_OPT, null, null, 84 '(isset({add}) || isset({update})) && isset({type})'. 85 ' && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_TELNET, 'type') 86 ], 87 'publickey' => [T_ZBX_STR, O_OPT, null, null, 88 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_SSH. 89 ' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 90 ], 91 'privatekey' => [T_ZBX_STR, O_OPT, null, null, 92 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_SSH. 93 ' && {authtype} == '.ITEM_AUTHTYPE_PUBLICKEY 94 ], 95 $paramsFieldName => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({add}) || isset({update}))'. 96 ' && isset({type}) && '.IN(ITEM_TYPE_SSH.','.ITEM_TYPE_DB_MONITOR.','. 97 ITEM_TYPE_TELNET.','.ITEM_TYPE_CALCULATED.','.ITEM_TYPE_SCRIPT, 'type' 98 ), 99 getParamFieldLabelByType(getRequest('type', 0)) 100 ], 101 'snmp_oid' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 102 '(isset({add}) || isset({update})) && isset({type})'. 103 ' && {type} == '.ITEM_TYPE_SNMP, 104 _('SNMP OID') 105 ], 106 'ipmi_sensor' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, 107 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_IPMI, 108 _('IPMI sensor') 109 ], 110 'trapper_hosts' => [T_ZBX_STR, O_OPT, null, null, 111 '(isset({add}) || isset({update})) && isset({type}) && {type} == 2' 112 ], 113 'lifetime' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 114 'evaltype' => [T_ZBX_INT, O_OPT, null, IN($evalTypes), 'isset({add}) || isset({update})'], 115 'formula' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 116 'conditions' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 117 'lld_macro_paths' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 118 'jmx_endpoint' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 119 '(isset({add}) || isset({update})) && isset({type}) && {type} == '.ITEM_TYPE_JMX 120 ], 121 'timeout' => [T_ZBX_TU, O_OPT, P_ALLOW_USER_MACRO, null, 122 '(isset({add}) || isset({update})) && isset({type})'. 123 ' && '.IN(ITEM_TYPE_HTTPAGENT.','.ITEM_TYPE_SCRIPT, 'type'), 124 _('Timeout') 125 ], 126 'url' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 127 '(isset({add}) || isset({update})) && isset({type})'. 128 ' && {type} == '.ITEM_TYPE_HTTPAGENT, 129 _('URL') 130 ], 131 'query_fields' => [T_ZBX_STR, O_OPT, null, null, null], 132 'parameters' => [T_ZBX_STR, O_OPT, null, null, null], 133 'posts' => [T_ZBX_STR, O_OPT, null, null, null], 134 'status_codes' => [T_ZBX_STR, O_OPT, null, null, null], 135 'follow_redirects' => [T_ZBX_INT, O_OPT, null, 136 IN([HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON]), 137 null 138 ], 139 'post_type' => [T_ZBX_INT, O_OPT, null, 140 IN([ZBX_POSTTYPE_RAW, ZBX_POSTTYPE_JSON, ZBX_POSTTYPE_XML]), 141 null 142 ], 143 'http_proxy' => [T_ZBX_STR, O_OPT, null, null, null], 144 'headers' => [T_ZBX_STR, O_OPT, null, null, null], 145 'retrieve_mode' => [T_ZBX_INT, O_OPT, null, 146 IN([HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, 147 HTTPTEST_STEP_RETRIEVE_MODE_BOTH 148 ]), 149 null 150 ], 151 'request_method' => [T_ZBX_INT, O_OPT, null, 152 IN([HTTPCHECK_REQUEST_GET, HTTPCHECK_REQUEST_POST, HTTPCHECK_REQUEST_PUT, 153 HTTPCHECK_REQUEST_HEAD 154 ]), 155 null 156 ], 157 'allow_traps' => [T_ZBX_INT, O_OPT, null, IN([HTTPCHECK_ALLOW_TRAPS_OFF, HTTPCHECK_ALLOW_TRAPS_ON]), 158 null 159 ], 160 'ssl_cert_file' => [T_ZBX_STR, O_OPT, null, null, null], 161 'ssl_key_file' => [T_ZBX_STR, O_OPT, null, null, null], 162 'ssl_key_password' => [T_ZBX_STR, O_OPT, null, null, null], 163 'verify_peer' => [T_ZBX_INT, O_OPT, null, 164 IN([HTTPTEST_VERIFY_PEER_OFF, HTTPTEST_VERIFY_PEER_ON]), 165 null 166 ], 167 'verify_host' => [T_ZBX_INT, O_OPT, null, 168 IN([HTTPTEST_VERIFY_HOST_OFF, HTTPTEST_VERIFY_HOST_ON]), 169 null 170 ], 171 'http_authtype' => [T_ZBX_INT, O_OPT, null, 172 IN([HTTPTEST_AUTH_NONE, HTTPTEST_AUTH_BASIC, HTTPTEST_AUTH_NTLM, 173 HTTPTEST_AUTH_KERBEROS, HTTPTEST_AUTH_DIGEST 174 ]), 175 null 176 ], 177 'http_username' => [T_ZBX_STR, O_OPT, null, null, 178 '(isset({add}) || isset({update})) && isset({http_authtype})'. 179 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 180 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 181 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 182 ' || {http_authtype} == '.HTTPTEST_AUTH_DIGEST. 183 ')', 184 _('Username') 185 ], 186 'http_password' => [T_ZBX_STR, O_OPT, null, null, 187 '(isset({add}) || isset({update})) && isset({http_authtype})'. 188 ' && ({http_authtype} == '.HTTPTEST_AUTH_BASIC. 189 ' || {http_authtype} == '.HTTPTEST_AUTH_NTLM. 190 ' || {http_authtype} == '.HTTPTEST_AUTH_KERBEROS. 191 ' || {http_authtype} == '.HTTPTEST_AUTH_DIGEST. 192 ')', 193 _('Password') 194 ], 195 'preprocessing' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, null], 196 'overrides' => [T_ZBX_STR, O_OPT, P_NO_TRIM, null, null], 197 'context' => [T_ZBX_STR, O_MAND, P_SYS, IN('"host", "template"'), null], 198 // actions 199 'action' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, 200 IN('"discoveryrule.massdelete","discoveryrule.massdisable",'. 201 '"discoveryrule.massenable","discoveryrule.masscheck_now"' 202 ), 203 null 204 ], 205 'g_hostdruleid' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 206 'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 207 'update' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 208 'clone' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 209 'delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 210 'cancel' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 211 'check_now' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 212 'form' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 213 'form_refresh' => [T_ZBX_INT, O_OPT, null, null, null], 214 // filter 215 'filter_set' => [T_ZBX_STR, O_OPT, null, null, null], 216 'filter_rst' => [T_ZBX_STR, O_OPT, null, null, null], 217 'filter_groupids' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 218 'filter_hostids' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 219 'filter_name' => [T_ZBX_STR, O_OPT, null, null, null], 220 'filter_key' => [T_ZBX_STR, O_OPT, null, null, null], 221 'filter_type' => [T_ZBX_INT, O_OPT, null, 222 IN([-1, ITEM_TYPE_ZABBIX, ITEM_TYPE_TRAPPER, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, 223 ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, 224 ITEM_TYPE_IPMI, ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX, 225 ITEM_TYPE_DEPENDENT, ITEM_TYPE_HTTPAGENT, ITEM_TYPE_SNMP, ITEM_TYPE_SCRIPT 226 ]), 227 null 228 ], 229 'filter_delay' => [T_ZBX_STR, O_OPT, P_UNSET_EMPTY, null, null, _('Update interval')], 230 'filter_lifetime' => [T_ZBX_STR, O_OPT, null, null, null], 231 'filter_snmp_oid' => [T_ZBX_STR, O_OPT, null, null, null], 232 'filter_state' => [T_ZBX_INT, O_OPT, null, IN([-1, ITEM_STATE_NORMAL, ITEM_STATE_NOTSUPPORTED]), 233 null 234 ], 235 'filter_status' => [T_ZBX_INT, O_OPT, null, IN([-1, ITEM_STATUS_ACTIVE, ITEM_STATUS_DISABLED]), 236 null 237 ], 238 // sort and sortorder 239 'sort' => [T_ZBX_STR, O_OPT, P_SYS, IN('"delay","key_","name","status","type"'), null], 240 'sortorder' => [T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'), null] 241]; 242check_fields($fields); 243 244$_REQUEST['params'] = getRequest($paramsFieldName, ''); 245unset($_REQUEST[$paramsFieldName]); 246$item = []; 247 248/* 249 * Permissions 250 */ 251$hostid = getRequest('hostid', 0); 252 253if (getRequest('itemid', false)) { 254 $item = API::DiscoveryRule()->get([ 255 'itemids' => getRequest('itemid'), 256 'output' => API_OUTPUT_EXTEND, 257 'selectHosts' => ['hostid', 'name', 'status', 'flags'], 258 'selectFilter' => ['formula', 'evaltype', 'conditions'], 259 'selectLLDMacroPaths' => ['lld_macro', 'path'], 260 'selectPreprocessing' => ['type', 'params', 'error_handler', 'error_handler_params'], 261 'selectOverrides' => ['name', 'step', 'stop', 'filter', 'operations'], 262 'editable' => true 263 ]); 264 $item = reset($item); 265 if (!$item) { 266 access_deny(); 267 } 268 $_REQUEST['hostid'] = $item['hostid']; 269 $host = reset($item['hosts']); 270 271 foreach ($item['overrides'] as &$override) { 272 if (!array_key_exists('operations', $override)) { 273 continue; 274 } 275 276 foreach ($override['operations'] as &$operation) { 277 if (array_key_exists('optag', $operation)) { 278 CArrayHelper::sort($operation['optag'], ['tag', 'value']); 279 $operation['optag'] = array_values($operation['optag']); 280 } 281 } 282 unset($operation); 283 } 284 unset($override); 285} 286elseif ($hostid) { 287 $hosts = API::Host()->get([ 288 'output' => ['hostid', 'name', 'status'], 289 'hostids' => $hostid, 290 'templated_hosts' => true, 291 'editable' => true 292 ]); 293 $host = reset($hosts); 294 if (!$host) { 295 access_deny(); 296 } 297} 298 299$prefix = (getRequest('context') === 'host') ? 'web.hosts.' : 'web.templates.'; 300 301/** 302 * Filter. 303 */ 304$sort_field = getRequest('sort', CProfile::get($prefix.$page['file'].'.sort', 'name')); 305$sort_order = getRequest('sortorder', CProfile::get($prefix.$page['file'].'.sortorder', ZBX_SORT_UP)); 306 307CProfile::update($prefix.$page['file'].'.sort', $sort_field, PROFILE_TYPE_STR); 308CProfile::update($prefix.$page['file'].'.sortorder', $sort_order, PROFILE_TYPE_STR); 309 310if (hasRequest('filter_set')) { 311 CProfile::updateArray($prefix.'host_discovery.filter.groupids', getRequest('filter_groupids', []), PROFILE_TYPE_ID); 312 CProfile::updateArray($prefix.'host_discovery.filter.hostids', getRequest('filter_hostids', []), PROFILE_TYPE_ID); 313 CProfile::update($prefix.'host_discovery.filter.name', getRequest('filter_name', ''), PROFILE_TYPE_STR); 314 CProfile::update($prefix.'host_discovery.filter.key', getRequest('filter_key', ''), PROFILE_TYPE_STR); 315 CProfile::update($prefix.'host_discovery.filter.type', getRequest('filter_type', -1), PROFILE_TYPE_INT); 316 CProfile::update($prefix.'host_discovery.filter.delay', getRequest('filter_delay', ''), PROFILE_TYPE_STR); 317 CProfile::update($prefix.'host_discovery.filter.lifetime', getRequest('filter_lifetime', ''), PROFILE_TYPE_STR); 318 CProfile::update($prefix.'host_discovery.filter.snmp_oid', getRequest('filter_snmp_oid', ''), PROFILE_TYPE_STR); 319 CProfile::update($prefix.'host_discovery.filter.state', getRequest('filter_state', -1), PROFILE_TYPE_INT); 320 CProfile::update($prefix.'host_discovery.filter.status', getRequest('filter_status', -1), PROFILE_TYPE_INT); 321} 322elseif (hasRequest('filter_rst')) { 323 CProfile::deleteIdx($prefix.'host_discovery.filter.groupids'); 324 325 if (count(CProfile::getArray($prefix.'host_discovery.filter.hostids', [])) != 1) { 326 CProfile::deleteIdx($prefix.'host_discovery.filter.hostids'); 327 } 328 329 CProfile::delete($prefix.'host_discovery.filter.name'); 330 CProfile::delete($prefix.'host_discovery.filter.key'); 331 CProfile::delete($prefix.'host_discovery.filter.type'); 332 CProfile::delete($prefix.'host_discovery.filter.delay'); 333 CProfile::delete($prefix.'host_discovery.filter.lifetime'); 334 CProfile::delete($prefix.'host_discovery.filter.snmp_oid'); 335 CProfile::delete($prefix.'host_discovery.filter.state'); 336 CProfile::delete($prefix.'host_discovery.filter.status'); 337} 338 339$filter = [ 340 'groups' => CProfile::getArray($prefix.'host_discovery.filter.groupids', []), 341 'hosts' => CProfile::getArray($prefix.'host_discovery.filter.hostids', []), 342 'name' => CProfile::get($prefix.'host_discovery.filter.name', ''), 343 'key' => CProfile::get($prefix.'host_discovery.filter.key', ''), 344 'type' => CProfile::get($prefix.'host_discovery.filter.type', -1), 345 'delay' => CProfile::get($prefix.'host_discovery.filter.delay', ''), 346 'lifetime' => CProfile::get($prefix.'host_discovery.filter.lifetime', ''), 347 'snmp_oid' => CProfile::get($prefix.'host_discovery.filter.snmp_oid', ''), 348 'state' => CProfile::get($prefix.'host_discovery.filter.state', -1), 349 'status' => CProfile::get($prefix.'host_discovery.filter.status', -1) 350]; 351 352$filter_groupids = []; 353$filter_hostids = []; 354 355// Get host groups. 356if ($filter['groups']) { 357 $filter['groups'] = CArrayHelper::renameObjectsKeys(API::HostGroup()->get([ 358 'output' => ['groupid', 'name'], 359 'groupids' => $filter['groups'], 360 'editable' => true, 361 'preservekeys' => true 362 ]), ['groupid' => 'id']); 363 364 $filter_groupids = getSubGroups(array_keys($filter['groups'])); 365} 366 367// Get hosts. 368if ($filter['hosts']) { 369 if (getRequest('context') === 'host') { 370 $filter['hosts'] = CArrayHelper::renameObjectsKeys(API::Host()->get([ 371 'output' => ['hostid', 'name'], 372 'hostids' => $filter['hosts'], 373 'editable' => true, 374 'preservekeys' => true 375 ]), ['hostid' => 'id']); 376 } 377 else { 378 $filter['hosts'] = CArrayHelper::renameObjectsKeys(API::Template()->get([ 379 'output' => ['templateid', 'name'], 380 'templateids' => $filter['hosts'], 381 'editable' => true, 382 'preservekeys' => true 383 ]), ['templateid' => 'id']); 384 } 385 386 $filter_hostids = array_keys($filter['hosts']); 387 388 sort($filter_hostids); 389} 390 391$checkbox_hash = crc32(implode('', $filter_hostids)); 392 393// Convert CR+LF to LF in preprocessing script. 394if (hasRequest('preprocessing')) { 395 foreach ($_REQUEST['preprocessing'] as &$step) { 396 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 397 $step['params'][0] = CRLFtoLF($step['params'][0]); 398 } 399 } 400 unset($step); 401} 402 403/* 404 * Actions 405 */ 406if (hasRequest('delete') && hasRequest('itemid')) { 407 $result = API::DiscoveryRule()->delete([getRequest('itemid')]); 408 409 if ($result) { 410 uncheckTableRows($checkbox_hash); 411 } 412 show_messages($result, _('Discovery rule deleted'), _('Cannot delete discovery rule')); 413 414 unset($_REQUEST['itemid'], $_REQUEST['form']); 415} 416elseif (hasRequest('check_now') && hasRequest('itemid')) { 417 $result = (bool) API::Task()->create([ 418 'type' => ZBX_TM_DATA_TYPE_CHECK_NOW, 419 'request' => [ 420 'itemid' => getRequest('itemid') 421 ] 422 ]); 423 424 show_messages($result, _('Request sent successfully'), _('Cannot send request')); 425} 426elseif (hasRequest('add') || hasRequest('update')) { 427 $result = true; 428 429 $delay = getRequest('delay', DB::getDefault('items', 'delay')); 430 $type = getRequest('type', ITEM_TYPE_ZABBIX); 431 432 /* 433 * "delay_flex" is a temporary field that collects flexible and scheduling intervals separated by a semicolon. 434 * In the end, custom intervals together with "delay" are stored in the "delay" variable. 435 */ 436 if ($type != ITEM_TYPE_TRAPPER && $type != ITEM_TYPE_SNMPTRAP 437 && ($type != ITEM_TYPE_ZABBIX_ACTIVE || strncmp(getRequest('key'), 'mqtt.get', 8) !== 0) 438 && hasRequest('delay_flex')) { 439 $intervals = []; 440 $simple_interval_parser = new CSimpleIntervalParser(['usermacros' => true]); 441 $time_period_parser = new CTimePeriodParser(['usermacros' => true]); 442 $scheduling_interval_parser = new CSchedulingIntervalParser(['usermacros' => true]); 443 444 foreach (getRequest('delay_flex') as $interval) { 445 if ($interval['type'] == ITEM_DELAY_FLEXIBLE) { 446 if ($interval['delay'] === '' && $interval['period'] === '') { 447 continue; 448 } 449 450 if ($simple_interval_parser->parse($interval['delay']) != CParser::PARSE_SUCCESS) { 451 $result = false; 452 info(_s('Invalid interval "%1$s".', $interval['delay'])); 453 break; 454 } 455 456 if ($time_period_parser->parse($interval['period']) != CParser::PARSE_SUCCESS) { 457 $result = false; 458 info(_s('Invalid interval "%1$s".', $interval['period'])); 459 break; 460 } 461 462 $intervals[] = $interval['delay'].'/'.$interval['period']; 463 } 464 else { 465 if ($interval['schedule'] === '') { 466 continue; 467 } 468 469 if ($scheduling_interval_parser->parse($interval['schedule']) != CParser::PARSE_SUCCESS) { 470 $result = false; 471 info(_s('Invalid interval "%1$s".', $interval['schedule'])); 472 break; 473 } 474 475 $intervals[] = $interval['schedule']; 476 } 477 } 478 479 if ($intervals) { 480 $delay .= ';'.implode(';', $intervals); 481 } 482 } 483 484 if ($result) { 485 $preprocessing = getRequest('preprocessing', []); 486 487 foreach ($preprocessing as &$step) { 488 switch ($step['type']) { 489 case ZBX_PREPROC_PROMETHEUS_TO_JSON: 490 $step['params'] = trim($step['params'][0]); 491 break; 492 493 case ZBX_PREPROC_XPATH: 494 case ZBX_PREPROC_JSONPATH: 495 case ZBX_PREPROC_VALIDATE_NOT_REGEX: 496 case ZBX_PREPROC_ERROR_FIELD_JSON: 497 case ZBX_PREPROC_ERROR_FIELD_XML: 498 case ZBX_PREPROC_THROTTLE_TIMED_VALUE: 499 case ZBX_PREPROC_SCRIPT: 500 $step['params'] = $step['params'][0]; 501 break; 502 503 case ZBX_PREPROC_REGSUB: 504 case ZBX_PREPROC_STR_REPLACE: 505 $step['params'] = implode("\n", $step['params']); 506 break; 507 508 // ZBX-16642 509 case ZBX_PREPROC_CSV_TO_JSON: 510 if (!array_key_exists(2, $step['params'])) { 511 $step['params'][2] = ZBX_PREPROC_CSV_NO_HEADER; 512 } 513 $step['params'] = implode("\n", $step['params']); 514 break; 515 516 default: 517 $step['params'] = ''; 518 } 519 520 $step += [ 521 'error_handler' => ZBX_PREPROC_FAIL_DEFAULT, 522 'error_handler_params' => '' 523 ]; 524 } 525 unset($step); 526 527 $newItem = [ 528 'itemid' => getRequest('itemid'), 529 'interfaceid' => getRequest('interfaceid'), 530 'name' => getRequest('name'), 531 'description' => getRequest('description'), 532 'key_' => getRequest('key'), 533 'hostid' => getRequest('hostid'), 534 'delay' => $delay, 535 'status' => getRequest('status', ITEM_STATUS_DISABLED), 536 'type' => getRequest('type'), 537 'snmp_oid' => getRequest('snmp_oid'), 538 'trapper_hosts' => getRequest('trapper_hosts'), 539 'authtype' => getRequest('authtype'), 540 'username' => getRequest('username'), 541 'password' => getRequest('password'), 542 'publickey' => getRequest('publickey'), 543 'privatekey' => getRequest('privatekey'), 544 'params' => getRequest('params'), 545 'ipmi_sensor' => getRequest('ipmi_sensor'), 546 'lifetime' => getRequest('lifetime') 547 ]; 548 549 if ($newItem['type'] == ITEM_TYPE_HTTPAGENT) { 550 $http_item = [ 551 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')), 552 'url' => getRequest('url'), 553 'query_fields' => getRequest('query_fields', []), 554 'posts' => getRequest('posts'), 555 'status_codes' => getRequest('status_codes', DB::getDefault('items', 'status_codes')), 556 'follow_redirects' => (int) getRequest('follow_redirects'), 557 'post_type' => (int) getRequest('post_type'), 558 'http_proxy' => getRequest('http_proxy'), 559 'headers' => getRequest('headers', []), 560 'retrieve_mode' => (int) getRequest('retrieve_mode'), 561 'request_method' => (int) getRequest('request_method'), 562 'output_format' => (int) getRequest('output_format'), 563 'allow_traps' => (int) getRequest('allow_traps', HTTPCHECK_ALLOW_TRAPS_OFF), 564 'ssl_cert_file' => getRequest('ssl_cert_file'), 565 'ssl_key_file' => getRequest('ssl_key_file'), 566 'ssl_key_password' => getRequest('ssl_key_password'), 567 'verify_peer' => (int) getRequest('verify_peer'), 568 'verify_host' => (int) getRequest('verify_host'), 569 'authtype' => getRequest('http_authtype', HTTPTEST_AUTH_NONE), 570 'username' => getRequest('http_username', ''), 571 'password' => getRequest('http_password', '') 572 ]; 573 $newItem = prepareItemHttpAgentFormData($http_item) + $newItem; 574 } 575 576 if ($newItem['type'] == ITEM_TYPE_SCRIPT) { 577 $script_item = [ 578 'parameters' => getRequest('parameters', []), 579 'timeout' => getRequest('timeout', DB::getDefault('items', 'timeout')) 580 ]; 581 582 $newItem = prepareScriptItemFormData($script_item) + $newItem; 583 } 584 585 if ($newItem['type'] == ITEM_TYPE_JMX) { 586 $newItem['jmx_endpoint'] = getRequest('jmx_endpoint', ''); 587 } 588 589 if (getRequest('type') == ITEM_TYPE_DEPENDENT) { 590 $newItem['master_itemid'] = getRequest('master_itemid'); 591 } 592 593 // add macros; ignore empty new macros 594 $lld_rule_filter = [ 595 'evaltype' => getRequest('evaltype'), 596 'conditions' => [] 597 ]; 598 $conditions = getRequest('conditions', []); 599 ksort($conditions); 600 $conditions = array_values($conditions); 601 foreach ($conditions as $condition) { 602 if (!zbx_empty($condition['macro'])) { 603 $condition['macro'] = mb_strtoupper($condition['macro']); 604 605 $lld_rule_filter['conditions'][] = $condition; 606 } 607 } 608 if ($lld_rule_filter['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) { 609 // if only one or no conditions are left, reset the evaltype to and/or and clear the formula 610 if (count($lld_rule_filter['conditions']) <= 1) { 611 $lld_rule_filter['formula'] = ''; 612 $lld_rule_filter['evaltype'] = CONDITION_EVAL_TYPE_AND_OR; 613 } 614 else { 615 $lld_rule_filter['formula'] = getRequest('formula'); 616 } 617 } 618 $newItem['filter'] = $lld_rule_filter; 619 620 $lld_macro_paths = getRequest('lld_macro_paths', []); 621 622 foreach ($lld_macro_paths as &$lld_macro_path) { 623 $lld_macro_path['lld_macro'] = mb_strtoupper($lld_macro_path['lld_macro']); 624 } 625 unset($lld_macro_path); 626 627 $newItem['lld_macro_paths'] = $lld_macro_paths; 628 629 foreach ($newItem['lld_macro_paths'] as $i => $lld_macro_path) { 630 if ($lld_macro_path['lld_macro'] === '' && $lld_macro_path['path'] === '') { 631 unset($newItem['lld_macro_paths'][$i]); 632 } 633 } 634 635 $overrides = getRequest('overrides', []); 636 $newItem['overrides'] = $overrides; 637 638 if (hasRequest('update')) { 639 DBstart(); 640 641 // Unset equal values if item script type and parameters have not changed. 642 $compare = function($arr, $arr2) { 643 return (array_combine(array_column($arr, 'name'), array_column($arr, 'value')) == 644 array_combine(array_column($arr2, 'name'), array_column($arr2, 'value')) 645 ); 646 }; 647 if ($newItem['type'] == ITEM_TYPE_SCRIPT && $newItem['type'] == $item['type'] 648 && $compare($item['parameters'], $newItem['parameters'])) { 649 unset($newItem['parameters']); 650 } 651 652 if ($newItem['type'] == $item['type']) { 653 $newItem = CArrayHelper::unsetEqualValues($newItem, $item, ['itemid']); 654 } 655 656 // don't update the filter if it hasn't changed 657 $conditionsChanged = false; 658 if (count($newItem['filter']['conditions']) != count($item['filter']['conditions'])) { 659 $conditionsChanged = true; 660 } 661 else { 662 $conditions = $item['filter']['conditions']; 663 foreach ($newItem['filter']['conditions'] as $i => $condition) { 664 if (CArrayHelper::unsetEqualValues($condition, $conditions[$i])) { 665 $conditionsChanged = true; 666 break; 667 } 668 } 669 } 670 $lld_rule_filter = CArrayHelper::unsetEqualValues($newItem['filter'], $item['filter']); 671 if (!isset($lld_rule_filter['evaltype']) && !isset($lld_rule_filter['formula']) && !$conditionsChanged) { 672 unset($newItem['filter']); 673 } 674 675 $lld_macro_paths_changed = false; 676 677 if (count($newItem['lld_macro_paths']) != count($item['lld_macro_paths'])) { 678 $lld_macro_paths_changed = true; 679 } 680 else { 681 $lld_macro_paths = array_values($item['lld_macro_paths']); 682 $newItem['lld_macro_paths'] = array_values($newItem['lld_macro_paths']); 683 684 foreach ($newItem['lld_macro_paths'] as $i => $lld_macro_path) { 685 if (CArrayHelper::unsetEqualValues($lld_macro_path, $lld_macro_paths[$i])) { 686 $lld_macro_paths_changed = true; 687 break; 688 } 689 } 690 } 691 692 if (!$lld_macro_paths_changed) { 693 unset($newItem['lld_macro_paths']); 694 } 695 696 if ($item['preprocessing'] !== $preprocessing) { 697 $newItem['preprocessing'] = $preprocessing; 698 } 699 700 $result = API::DiscoveryRule()->update($newItem); 701 $result = DBend($result); 702 } 703 else { 704 if (!$newItem['lld_macro_paths']) { 705 unset($newItem['lld_macro_paths']); 706 } 707 708 if ($preprocessing) { 709 $newItem['preprocessing'] = $preprocessing; 710 } 711 712 $result = API::DiscoveryRule()->create([$newItem]); 713 } 714 } 715 716 if (hasRequest('add')) { 717 show_messages($result, _('Discovery rule created'), _('Cannot add discovery rule')); 718 } 719 else { 720 show_messages($result, _('Discovery rule updated'), _('Cannot update discovery rule')); 721 } 722 723 if ($result) { 724 unset($_REQUEST['itemid'], $_REQUEST['form']); 725 uncheckTableRows($checkbox_hash); 726 } 727} 728elseif (hasRequest('action') && str_in_array(getRequest('action'), ['discoveryrule.massenable', 'discoveryrule.massdisable']) && hasRequest('g_hostdruleid')) { 729 $itemids = getRequest('g_hostdruleid'); 730 $status = (getRequest('action') === 'discoveryrule.massenable') ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED; 731 732 $lld_rules = []; 733 foreach ($itemids as $itemid) { 734 $lld_rules[] = ['itemid' => $itemid, 'status' => $status]; 735 } 736 737 $result = (bool) API::DiscoveryRule()->update($lld_rules); 738 739 if ($result) { 740 uncheckTableRows($checkbox_hash); 741 } 742 743 $updated = count($itemids); 744 745 $messageSuccess = ($status == ITEM_STATUS_ACTIVE) 746 ? _n('Discovery rule enabled', 'Discovery rules enabled', $updated) 747 : _n('Discovery rule disabled', 'Discovery rules disabled', $updated); 748 $messageFailed = ($status == ITEM_STATUS_ACTIVE) 749 ? _n('Cannot enable discovery rule', 'Cannot enable discovery rules', $updated) 750 : _n('Cannot disable discovery rule', 'Cannot disable discovery rules', $updated); 751 752 show_messages($result, $messageSuccess, $messageFailed); 753} 754elseif (hasRequest('action') && getRequest('action') === 'discoveryrule.massdelete' && hasRequest('g_hostdruleid')) { 755 $result = API::DiscoveryRule()->delete(getRequest('g_hostdruleid')); 756 757 if ($result) { 758 uncheckTableRows($checkbox_hash); 759 } 760 show_messages($result, _('Discovery rules deleted'), _('Cannot delete discovery rules')); 761} 762elseif (hasRequest('action') && getRequest('action') === 'discoveryrule.masscheck_now' && hasRequest('g_hostdruleid')) { 763 $tasks = []; 764 765 foreach (getRequest('g_hostdruleid') as $taskid) { 766 $tasks[] = [ 767 'type' => ZBX_TM_DATA_TYPE_CHECK_NOW, 768 'request' => [ 769 'itemid' => $taskid 770 ] 771 ]; 772 } 773 774 $result = (bool) API::Task()->create($tasks); 775 776 if ($result) { 777 uncheckTableRows($checkbox_hash); 778 } 779 780 show_messages($result, _('Request sent successfully'), _('Cannot send request')); 781} 782 783if (hasRequest('action') && hasRequest('g_hostdruleid') && !$result) { 784 $hostdrules = API::DiscoveryRule()->get([ 785 'output' => [], 786 'itemids' => getRequest('g_hostdruleid'), 787 'editable' => true 788 ]); 789 uncheckTableRows($checkbox_hash, zbx_objectValues($hostdrules, 'itemid')); 790} 791 792/* 793 * Display 794 */ 795if (hasRequest('form')) { 796 $has_errors = false; 797 $form_item = (hasRequest('itemid') && !hasRequest('clone')) ? $item : []; 798 $master_itemid = $form_item && !hasRequest('form_refresh') 799 ? $form_item['master_itemid'] 800 : getRequest('master_itemid'); 801 802 if (getRequest('type', $form_item ? $form_item['type'] : null) == ITEM_TYPE_DEPENDENT && $master_itemid != 0) { 803 $db_master_items = API::Item()->get([ 804 'output' => ['itemid', 'type', 'hostid', 'name', 'key_'], 805 'itemids' => $master_itemid, 806 'webitems' => true 807 ]); 808 809 if (!$db_master_items) { 810 show_messages(false, '', _('No permissions to referred object or it does not exist!')); 811 $has_errors = true; 812 } 813 else { 814 $form_item['master_item'] = $db_master_items[0]; 815 } 816 } 817 818 $data = getItemFormData($form_item, ['form' => getRequest('form'), 'is_discovery_rule' => true]); 819 $data['lifetime'] = getRequest('lifetime', DB::getDefault('items', 'lifetime')); 820 $data['evaltype'] = getRequest('evaltype'); 821 $data['formula'] = getRequest('formula'); 822 $data['conditions'] = getRequest('conditions', []); 823 $data['lld_macro_paths'] = getRequest('lld_macro_paths', []); 824 $data['overrides'] = getRequest('overrides', []); 825 $data['host'] = $host; 826 $data['preprocessing_test_type'] = CControllerPopupItemTestEdit::ZBX_TEST_TYPE_LLD; 827 $data['preprocessing_types'] = CDiscoveryRule::SUPPORTED_PREPROCESSING_TYPES; 828 $data['display_interfaces'] = ($host['status'] == HOST_STATUS_MONITORED 829 || $host['status'] == HOST_STATUS_NOT_MONITORED 830 ); 831 832 if (!hasRequest('form_refresh')) { 833 foreach ($data['preprocessing'] as &$step) { 834 if ($step['type'] == ZBX_PREPROC_SCRIPT) { 835 $step['params'] = [$step['params'], '']; 836 } 837 else { 838 $step['params'] = explode("\n", $step['params']); 839 } 840 } 841 unset($step); 842 } 843 844 // update form 845 if (hasRequest('itemid') && !getRequest('form_refresh')) { 846 $data['lifetime'] = $item['lifetime']; 847 $data['evaltype'] = $item['filter']['evaltype']; 848 $data['formula'] = $item['filter']['formula']; 849 $data['conditions'] = $item['filter']['conditions']; 850 $data['lld_macro_paths'] = $item['lld_macro_paths']; 851 $data['overrides'] = $item['overrides']; 852 // Sort overrides to be listed in step order. 853 CArrayHelper::sort($data['overrides'], ['step']); 854 } 855 // clone form 856 elseif (hasRequest('clone')) { 857 unset($data['itemid']); 858 $data['form'] = 'clone'; 859 } 860 861 if ($data['type'] != ITEM_TYPE_JMX) { 862 $data['jmx_endpoint'] = ZBX_DEFAULT_JMX_ENDPOINT; 863 } 864 865 // render view 866 if (!$has_errors) { 867 echo (new CView('configuration.host.discovery.edit', $data))->getOutput(); 868 } 869} 870else { 871 $data = [ 872 'filter' => $filter, 873 'hostid' => (count($filter_hostids) == 1) ? reset($filter_hostids) : 0, 874 'sort' => $sort_field, 875 'sortorder' => $sort_order, 876 'profileIdx' => $prefix.'host_discovery.filter', 877 'active_tab' => CProfile::get($prefix.'host_discovery.filter.active', 1), 878 'checkbox_hash' => $checkbox_hash, 879 'is_template' => true, 880 'context' => getRequest('context') 881 ]; 882 883 // Select LLD rules. 884 $options = [ 885 'output' => API_OUTPUT_EXTEND, 886 'selectHosts' => ['hostid', 'name', 'status', 'flags'], 887 'selectItems' => API_OUTPUT_COUNT, 888 'selectGraphs' => API_OUTPUT_COUNT, 889 'selectTriggers' => API_OUTPUT_COUNT, 890 'selectHostPrototypes' => API_OUTPUT_COUNT, 891 'editable' => true, 892 'templated' => ($data['context'] === 'template'), 893 'filter' => [], 894 'search' => [], 895 'sortfield' => $sort_field, 896 'limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1 897 ]; 898 899 if ($filter_groupids) { 900 $options['groupids'] = $filter_groupids; 901 } 902 903 if ($filter_hostids) { 904 $options['hostids'] = $filter_hostids; 905 } 906 907 if ($filter['name'] !== '') { 908 $options['search']['name'] = $filter['name']; 909 } 910 911 if ($filter['key'] !== '') { 912 $options['search']['key_'] = $filter['key']; 913 } 914 915 if ($filter['type'] != -1) { 916 $options['filter']['type'] = $filter['type']; 917 } 918 919 /* 920 * Trapper and SNMP trap items contain zeros in "delay" field and, if no specific type is set, look in item types 921 * other than trapper and SNMP trap that allow zeros. For example, when a flexible interval is used. Since trapper 922 * and SNMP trap items contain zeros, but those zeros should not be displayed, they cannot be filtered by entering 923 * either zero or any other number in filter field. 924 */ 925 if ($filter['delay'] !== '') { 926 if ($filter['type'] == -1 && $filter['delay'] == 0) { 927 $options['filter']['type'] = [ITEM_TYPE_ZABBIX, ITEM_TYPE_SIMPLE, ITEM_TYPE_INTERNAL, 928 ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_EXTERNAL, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_IPMI, 929 ITEM_TYPE_SSH, ITEM_TYPE_TELNET, ITEM_TYPE_JMX 930 ]; 931 $options['filter']['delay'] = $filter['delay']; 932 } 933 elseif ($filter['type'] == ITEM_TYPE_TRAPPER || $filter['type'] == ITEM_TYPE_DEPENDENT 934 || ($filter['type'] == ITEM_TYPE_ZABBIX_ACTIVE && strncmp($filter['key'], 'mqtt.get', 8) === 0)) { 935 $options['filter']['delay'] = -1; 936 } 937 else { 938 $options['filter']['delay'] = $filter['delay']; 939 } 940 } 941 942 if ($filter['lifetime'] !== '') { 943 $options['filter']['lifetime'] = $filter['lifetime']; 944 } 945 946 if ($filter['snmp_oid'] !== '') { 947 $options['filter']['snmp_oid'] = $filter['snmp_oid']; 948 } 949 950 if ($filter['status'] != -1) { 951 $options['filter']['status'] = $filter['status']; 952 } 953 954 if ($filter['state'] != -1) { 955 $options['filter']['status'] = ITEM_STATUS_ACTIVE; 956 $options['filter']['state'] = $filter['state']; 957 } 958 959 $data['discoveries'] = API::DiscoveryRule()->get($options); 960 $data['discoveries'] = CMacrosResolverHelper::resolveItemNames($data['discoveries']); 961 962 switch ($sort_field) { 963 case 'delay': 964 orderItemsByDelay($data['discoveries'], $sort_order, ['usermacros' => true]); 965 break; 966 967 case 'status': 968 orderItemsByStatus($data['discoveries'], $sort_order); 969 break; 970 971 default: 972 order_result($data['discoveries'], $sort_field, $sort_order); 973 } 974 975 $data['discoveries'] = expandItemNamesWithMasterItems($data['discoveries'], 'items'); 976 977 // Set is_template false, when one of hosts is not template. 978 if ($data['discoveries']) { 979 $hosts_status = []; 980 foreach ($data['discoveries'] as $discovery) { 981 $hosts_status[$discovery['hosts'][0]['status']] = true; 982 } 983 foreach ($hosts_status as $key => $value) { 984 if ($key != HOST_STATUS_TEMPLATE) { 985 $data['is_template'] = false; 986 break; 987 } 988 } 989 } 990 991 // pager 992 if (hasRequest('page')) { 993 $page_num = getRequest('page'); 994 } 995 elseif (isRequestMethod('get') && !hasRequest('cancel')) { 996 $page_num = 1; 997 } 998 else { 999 $page_num = CPagerHelper::loadPage($page['file']); 1000 } 1001 1002 CPagerHelper::savePage($page['file'], $page_num); 1003 1004 $data['paging'] = CPagerHelper::paginate($page_num, $data['discoveries'], $sort_order, 1005 (new CUrl('host_discovery.php'))->setArgument('context', $data['context']) 1006 ); 1007 1008 $data['parent_templates'] = getItemParentTemplates($data['discoveries'], ZBX_FLAG_DISCOVERY_RULE); 1009 $data['allowed_ui_conf_templates'] = CWebUser::checkAccess(CRoleHelper::UI_CONFIGURATION_TEMPLATES); 1010 1011 // render view 1012 echo (new CView('configuration.host.discovery.list', $data))->getOutput(); 1013} 1014 1015require_once dirname(__FILE__).'/include/page_footer.php'; 1016