// get application ids $applications = API::Application()->get(array('hostids' => $pageFilter->hostid > 0 ? $pageFilter->hostid : null, 'groupids' => $pageFilter->groupid > 0 ? $pageFilter->groupid : null, 'output' => array('applicationid'), 'editable' => true, 'sortfield' => $sortField, 'limit' => $config['search_limit'] + 1)); $applicationIds = zbx_objectValues($applications, 'applicationid'); // get applications $data['applications'] = API::Application()->get(array('applicationids' => $applicationIds, 'output' => API_OUTPUT_EXTEND, 'selectItems' => array('itemid'), 'selectHost' => array('hostid', 'name'))); order_result($data['applications'], $sortField, $sortOrder); // fetch template application source parents $applicationSourceParentIds = getApplicationSourceParentIds($applicationIds); $parentAppIds = array(); foreach ($applicationSourceParentIds as $applicationParentIds) { foreach ($applicationParentIds as $parentId) { $parentAppIds[$parentId] = $parentId; } } if ($parentAppIds) { $parentTemplates = DBfetchArrayAssoc(DBselect('SELECT a.applicationid,h.hostid,h.name' . ' FROM applications a,hosts h' . ' WHERE a.hostid=h.hostid' . ' AND ' . dbConditionInt('a.applicationid', $parentAppIds)), 'applicationid'); foreach ($data['applications'] as &$application) { if ($application['templateids'] && isset($applicationSourceParentIds[$application['applicationid']])) { foreach ($applicationSourceParentIds[$application['applicationid']] as $parentAppId) { $application['sourceTemplates'][] = $parentTemplates[$parentAppId]; } } } } } else { $data['applications'] = array(); } // get paging $data['paging'] = getPagingLine($data['applications'], $sortOrder); // render view $applicationView = new CView('configuration.application.list', $data);
/** * Delete proxy. * * @param array $proxyIds * * @return array */ public function delete(array $proxyIds) { $this->validateDelete($proxyIds); $dbProxies = DBselect('SELECT h.hostid,h.host' . ' FROM hosts h' . ' WHERE ' . dbConditionInt('h.hostid', $proxyIds)); $dbProxies = DBfetchArrayAssoc($dbProxies, 'hostid'); $actionIds = array(); // get conditions $dbActions = DBselect('SELECT DISTINCT c.actionid' . ' FROM conditions c' . ' WHERE c.conditiontype=' . CONDITION_TYPE_PROXY . ' AND ' . dbConditionString('c.value', $proxyIds)); while ($dbAction = DBfetch($dbActions)) { $actionIds[$dbAction['actionid']] = $dbAction['actionid']; } if ($actionIds) { DB::update('actions', array('values' => array('status' => ACTION_STATUS_DISABLED), 'where' => array('actionid' => $actionIds))); } // delete action conditions DB::delete('conditions', array('conditiontype' => CONDITION_TYPE_PROXY, 'value' => $proxyIds)); // delete interface DB::delete('interface', array('hostid' => $proxyIds)); // delete host DB::delete('hosts', array('hostid' => $proxyIds)); // TODO: remove info from API foreach ($dbProxies as $proxy) { info(_s('Deleted: Proxy "%1$s".', $proxy['host'])); add_audit(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_PROXY, '[' . $proxy['host'] . '] [' . $proxy['hostid'] . ']'); } return array('proxyids' => $proxyIds); }
protected function applyPostSqlFiltering(array $triggers, array $options) { $triggers = zbx_toHash($triggers, 'triggerid'); // unset triggers which depend on at least one problem trigger upstream into dependency tree if ($options['skipDependent'] !== null) { // Result trigger IDs of all triggers in results. $resultTriggerIds = zbx_objectValues($triggers, 'triggerid'); // Will contain IDs of all triggers on which some other trigger depends. $allUpTriggerIds = []; // Trigger dependency map. $downToUpTriggerIds = []; // Values (state) of each "up" trigger ID is stored in here. $upTriggerValues = []; // Will contain IDs of all triggers either disabled directly, or by having disabled item or disabled host. $disabledTriggerIds = []; // First loop uses result trigger IDs. $triggerIds = $resultTriggerIds; do { // Fetch all dependency records where "down" trigger IDs are in current iteration trigger IDs. $dbResult = DBselect('SELECT d.triggerid_down,d.triggerid_up,t.value' . ' FROM trigger_depends d,triggers t' . ' WHERE d.triggerid_up=t.triggerid' . ' AND ' . dbConditionInt('d.triggerid_down', $triggerIds)); // Add trigger IDs as keys and empty arrays as values. $downToUpTriggerIds = $downToUpTriggerIds + array_fill_keys($triggerIds, []); $triggerIds = []; while ($dependency = DBfetch($dbResult)) { // Trigger ID for "down" trigger, which has dependencies. $downTriggerId = $dependency['triggerid_down']; // Trigger ID for "up" trigger, on which the other ("up") trigger depends. $upTriggerId = $dependency['triggerid_up']; // Add "up" trigger ID to mapping. We also index by $upTrigger because later these arrays // are combined with + and this way indexes and values do not break. $downToUpTriggerIds[$downTriggerId][$upTriggerId] = $upTriggerId; // Add ID of this "up" trigger to all known "up" triggers. $allUpTriggerIds[] = $upTriggerId; // Remember value of this "up" trigger. $upTriggerValues[$upTriggerId] = $dependency['value']; // Add ID of this "up" trigger to the list of trigger IDs which should be mapped. $triggerIds[] = $upTriggerId; } } while ($triggerIds); // Fetch trigger IDs for triggers that are disabled, have disabled items or disabled item hosts. $dbResult = DBSelect('SELECT t.triggerid' . ' FROM triggers t,functions f,items i,hosts h' . ' WHERE t.triggerid=f.triggerid' . ' AND f.itemid=i.itemid' . ' AND i.hostid=h.hostid' . ' AND (' . 'i.status=' . ITEM_STATUS_DISABLED . ' OR h.status=' . HOST_STATUS_NOT_MONITORED . ' OR t.status=' . TRIGGER_STATUS_DISABLED . ')' . ' AND ' . dbConditionInt('t.triggerid', $allUpTriggerIds)); while ($row = DBfetch($dbResult)) { $resultTriggerId = $row['triggerid']; $disabledTriggerIds[$resultTriggerId] = $resultTriggerId; } // Now process all mapped dependencies and unset any disabled "up" triggers so they do not participate in // decisions regarding nesting resolution in next step. foreach ($downToUpTriggerIds as $downTriggerId => $upTriggerIds) { $upTriggerIdsToUnset = []; foreach ($upTriggerIds as $upTriggerId) { if (isset($disabledTriggerIds[$upTriggerId])) { unset($downToUpTriggerIds[$downTriggerId][$upTriggerId]); } } } // Resolve dependencies for all result set triggers. foreach ($resultTriggerIds as $resultTriggerId) { // We start with result trigger. $triggerIds = [$resultTriggerId]; // This also is unrolled recursive function and is repeated until there are no more trigger IDs to // check, add and resolve. do { $nextTriggerIds = []; foreach ($triggerIds as $triggerId) { // Loop through all "up" triggers. foreach ($downToUpTriggerIds[$triggerId] as $upTriggerId) { if ($downToUpTriggerIds[$upTriggerId]) { // If there this "up" trigger has "up" triggers of it's own, merge them and proceed with recursion. $downToUpTriggerIds[$resultTriggerId] += $downToUpTriggerIds[$upTriggerId]; // Add trigger ID to be processed in next loop iteration. $nextTriggerIds[] = $upTriggerId; } } } $triggerIds = $nextTriggerIds; } while ($triggerIds); } // Clean result set. foreach ($resultTriggerIds as $resultTriggerId) { foreach ($downToUpTriggerIds[$resultTriggerId] as $upTriggerId) { // If "up" trigger is in problem state, dependent trigger should not be returned and is removed // from results. if ($upTriggerValues[$upTriggerId] == TRIGGER_VALUE_TRUE) { unset($triggers[$resultTriggerId]); } } // Check if result trigger is disabled and if so, remove from results. if (isset($disabledTriggerIds[$resultTriggerId])) { unset($triggers[$resultTriggerId]); } } } // withLastEventUnacknowledged if (!is_null($options['withLastEventUnacknowledged'])) { $triggerIds = zbx_objectValues($triggers, 'triggerid'); $eventIds = []; $eventsDb = DBselect('SELECT MAX(e.eventid) AS eventid,e.objectid' . ' FROM events e' . ' WHERE e.object=' . EVENT_OBJECT_TRIGGER . ' AND e.source=' . EVENT_SOURCE_TRIGGERS . ' AND ' . dbConditionInt('e.objectid', $triggerIds) . ' AND ' . dbConditionInt('e.value', [TRIGGER_VALUE_TRUE]) . ' GROUP BY e.objectid'); while ($event = DBfetch($eventsDb)) { $eventIds[] = $event['eventid']; } $correctTriggerIds = DBfetchArrayAssoc(DBselect('SELECT e.objectid' . ' FROM events e ' . ' WHERE ' . dbConditionInt('e.eventid', $eventIds) . ' AND e.acknowledged=0'), 'objectid'); foreach ($triggers as $triggerId => $trigger) { if (!isset($correctTriggerIds[$triggerId])) { unset($triggers[$triggerId]); } } } return $triggers; }
/** * Resolve functional macros, like {hostname:key.function(param)}. * If macro can not be resolved it is replaced with UNRESOLVED_MACRO_STRING string i.e. "*UNKNOWN*". * * Supports function "last", "min", "max" and "avg". * Supports seconds as parameters, except "last" function. * Second parameter like {hostname:key.last(0,86400) and offsets like {hostname:key.last(#1)} are not supported. * Supports postfixes s,m,h,d and w for parameter. * * @param array $strList list of string in which macros should be resolved * @param array $itemsList list of lists of graph items * @param int $items[n][m]['hostid'] n-th graph m-th item corresponding host Id * @param string $items[n][m]['host'] n-th graph m-th item corresponding host name * * @return array list of strings with macros replaced with corresponding values */ private function resolveGraphsFunctionalItemMacros($strList, $itemsList) { // retrieve all string macros and all host-key pairs $hostKeyPairs = $matchesList = array(); $items = reset($itemsList); foreach ($strList as $str) { // extract all macros into $matches - keys: macros, hosts, keys, functions and parameters are used // searches for macros, for example, "{somehost:somekey["param[123]"].min(10m)}" preg_match_all('/(?P<macros>{' . '(?P<hosts>(' . ZBX_PREG_HOST_FORMAT . '|({(' . self::PATTERN_HOST_INTERNAL . ')' . self::PATTERN_MACRO_PARAM . '}))):' . '(?P<keys>' . ZBX_PREG_ITEM_KEY_FORMAT . ')\\.' . '(?P<functions>(last|max|min|avg))\\(' . '(?P<parameters>([0-9]+[' . ZBX_TIME_SUFFIXES . ']?)?)' . '\\)}{1})/Uux', $str, $matches, PREG_OFFSET_CAPTURE); if (!empty($matches['hosts'])) { foreach ($matches['hosts'] as $i => $host) { $matches['hosts'][$i][0] = $this->resolveGraphPositionalMacros($host[0], $items); if ($matches['hosts'][$i][0] !== UNRESOLVED_MACRO_STRING) { if (!isset($hostKeyPairs[$matches['hosts'][$i][0]])) { $hostKeyPairs[$matches['hosts'][$i][0]] = array(); } $hostKeyPairs[$matches['hosts'][$i][0]][$matches['keys'][$i][0]] = 1; } } $matchesList[] = $matches; $items = next($itemsList); } } // stop, if no macros found if (empty($matchesList)) { return $strList; } // build item retrieval query from host-key pairs $query = 'SELECT h.host,i.key_,i.itemid,i.value_type,i.units,i.valuemapid' . ' FROM items i, hosts h' . ' WHERE i.hostid=h.hostid AND ('; foreach ($hostKeyPairs as $host => $keys) { $query .= '(h.host=' . zbx_dbstr($host) . ' AND i.key_ IN('; foreach ($keys as $key => $val) { $query .= zbx_dbstr($key) . ','; } $query = substr($query, 0, -1) . ')) OR '; } $query = substr($query, 0, -4) . ')'; // get necessary items for all graph strings $items = DBfetchArrayAssoc(DBselect($query), 'itemid'); $allowedItems = API::Item()->get(array('itemids' => array_keys($items), 'webitems' => true, 'output' => array('itemid', 'value_type', 'lastvalue', 'lastclock'), 'preservekeys' => true)); // map item data only for allowed items foreach ($items as $item) { if (isset($allowedItems[$item['itemid']])) { $item['lastvalue'] = $allowedItems[$item['itemid']]['lastvalue']; $item['lastclock'] = $allowedItems[$item['itemid']]['lastclock']; $hostKeyPairs[$item['host']][$item['key_']] = $item; } } // replace macros with their corresponding values in graph strings $matches = reset($matchesList); foreach ($strList as &$str) { // iterate array backwards! $i = count($matches['macros']); while ($i--) { $host = $matches['hosts'][$i][0]; $key = $matches['keys'][$i][0]; $function = $matches['functions'][$i][0]; $parameter = $matches['parameters'][$i][0]; // host is real and item exists and has permissions if ($host !== UNRESOLVED_MACRO_STRING && is_array($hostKeyPairs[$host][$key])) { $item = $hostKeyPairs[$host][$key]; // macro function is "last" if ($function == 'last') { $value = $item['lastclock'] > 0 ? formatHistoryValue($item['lastvalue'], $item) : UNRESOLVED_MACRO_STRING; } else { $value = getItemFunctionalValue($item, $function, $parameter); } } else { $value = UNRESOLVED_MACRO_STRING; } $str = substr_replace($str, $value, $matches['macros'][$i][1], strlen($matches['macros'][$i][0])); } $matches = next($matchesList); } unset($str); return $strList; }
/** * Resolve functional macros, like {hostname:key.function(param)}. * If macro can not be resolved it is replaced with UNRESOLVED_MACRO_STRING string i.e. "*UNKNOWN*". * * Supports function "last", "min", "max" and "avg". * Supports seconds as parameters, except "last" function. * Second parameter like {hostname:key.last(0,86400) and offsets like {hostname:key.last(#1)} are not supported. * Supports postfixes s,m,h,d and w for parameter. * * @param array $sourceStringList list of strings from graphs in which macros should be resolved * @param array $itemsList list of lists of graph items used in graphs * @param int $itemsList[n][m]['hostid'] n-th graph m-th item corresponding host ID * @param string $itemsList[n][m]['host'] n-th graph m-th item corresponding host name * * @return array list of strings, possibly with macros in them replaced with resolved values */ private function resolveGraphsFunctionalItemMacros(array $sourceStringList, array $itemsList) { $hostKeyPairs = []; $matchesList = []; $items = reset($itemsList); foreach ($sourceStringList as $sourceString) { /* * Extract all macros into $matches - keys: macros, hosts, keys, functions and parameters are used * searches for macros, for example, "{somehost:somekey["param[123]"].min(10m)}" */ preg_match_all('/(?P<macros>{' . '(?P<hosts>(' . ZBX_PREG_HOST_FORMAT . '|({(' . self::PATTERN_HOST_INTERNAL . ')' . self::PATTERN_MACRO_PARAM . '}))):' . '(?P<keys>' . ZBX_PREG_ITEM_KEY_FORMAT . ')\\.' . '(?P<functions>(last|max|min|avg))\\(' . '(?P<parameters>([0-9]+[' . ZBX_TIME_SUFFIXES . ']?)?)' . '\\)}{1})/Uux', $sourceString, $matches, PREG_OFFSET_CAPTURE); foreach ($matches['hosts'] as $i => &$host) { $host[0] = $this->resolveGraphPositionalMacros($host[0], $items); if ($host[0] !== UNRESOLVED_MACRO_STRING) { // Take note that resolved host has a such key (and it is used in a macro). if (!isset($hostKeyPairs[$host[0]])) { $hostKeyPairs[$host[0]] = []; } $hostKeyPairs[$host[0]][$matches['keys'][$i][0]] = true; } } unset($host); // Remember match for later use. $matchesList[] = $matches; $items = next($itemsList); } /* * If no host/key pairs found in macro-like parts of source string then there is nothing to do but return * source strings as they are. */ if (!$hostKeyPairs) { return $sourceStringList; } // Build item retrieval query from host-key pairs and get all necessary items for all source strings. $queryParts = []; foreach ($hostKeyPairs as $host => $keys) { $queryParts[] = '(h.host=' . zbx_dbstr($host) . ' AND ' . dbConditionString('i.key_', array_keys($keys)) . ')'; } $items = DBfetchArrayAssoc(DBselect('SELECT h.host,i.key_,i.itemid,i.value_type,i.units,i.valuemapid' . ' FROM items i,hosts h' . ' WHERE i.hostid=h.hostid' . ' AND (' . join(' OR ', $queryParts) . ')'), 'itemid'); // Get items for which user has permission. $allowedItems = API::Item()->get(['itemids' => array_keys($items), 'webitems' => true, 'output' => ['itemid', 'value_type', 'lastvalue', 'lastclock'], 'preservekeys' => true]); // Get map item data only for those allowed items and set "value_type" for allowed items. foreach ($items as $item) { if (isset($allowedItems[$item['itemid']])) { $item['lastvalue'] = $allowedItems[$item['itemid']]['lastvalue']; $item['lastclock'] = $allowedItems[$item['itemid']]['lastclock']; $hostKeyPairs[$item['host']][$item['key_']] = $item; } } /* * Replace macros with their corresponding values in graph strings and replace macros with their resolved * values in source strings. */ $matches = reset($matchesList); foreach ($sourceStringList as &$sourceString) { /* * We iterate array backwards so that replacing unresolved macro string (see lower) with actual value * does not mess up originally captured offsets. */ $i = count($matches['macros']); while ($i--) { $host = $matches['hosts'][$i][0]; $key = $matches['keys'][$i][0]; $function = $matches['functions'][$i][0]; $parameter = $matches['parameters'][$i][0]; // If host is real and item exists and has permissions. if ($host !== UNRESOLVED_MACRO_STRING && is_array($hostKeyPairs[$host][$key])) { $item = $hostKeyPairs[$host][$key]; // Macro function is "last". if ($function == 'last') { $value = $item['lastclock'] > 0 ? formatHistoryValue($item['lastvalue'], $item) : UNRESOLVED_MACRO_STRING; } else { $value = getItemFunctionalValue($item, $function, $parameter); } } else { $value = UNRESOLVED_MACRO_STRING; } /* * Replace macro string with actual, resolved string value. This is safe because we start from far * end of $sourceString. */ $sourceString = substr_replace($sourceString, $value, $matches['macros'][$i][1], strlen($matches['macros'][$i][0])); } // Advance to next matches for next $sourceString. $matches = next($matchesList); } unset($sourceString); return $sourceStringList; }
/** * Delete proxy. * * @param string|array $proxyIds * * @return array */ public function delete($proxyIds) { $proxyIds = zbx_toArray($proxyIds); // deprecated input support if ($proxyIds && is_array($proxyIds[0])) { $this->deprecated('Passing objects is deprecated, use an array of IDs instead.'); foreach ($proxyIds as $proxyId) { if (!check_db_fields(array('proxyid' => null), $proxyId)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No proxy ID given.')); } } $proxyIds = zbx_objectValues($proxyIds, 'proxyid'); } $this->validateDelete($proxyIds); $dbProxies = DBselect('SELECT h.hostid,h.host' . ' FROM hosts h' . ' WHERE ' . dbConditionInt('h.hostid', $proxyIds)); $dbProxies = DBfetchArrayAssoc($dbProxies, 'hostid'); $actionIds = array(); // get conditions $dbActions = DBselect('SELECT DISTINCT c.actionid' . ' FROM conditions c' . ' WHERE c.conditiontype=' . CONDITION_TYPE_PROXY . ' AND ' . dbConditionString('c.value', $proxyIds)); while ($dbAction = DBfetch($dbActions)) { $actionIds[$dbAction['actionid']] = $dbAction['actionid']; } if ($actionIds) { DB::update('actions', array('values' => array('status' => ACTION_STATUS_DISABLED), 'where' => array('actionid' => $actionIds))); } // delete action conditions DB::delete('conditions', array('conditiontype' => CONDITION_TYPE_PROXY, 'value' => $proxyIds)); // delete interface DB::delete('interface', array('hostid' => $proxyIds)); // delete host DB::delete('hosts', array('hostid' => $proxyIds)); // TODO: remove info from API foreach ($dbProxies as $proxy) { info(_s('Deleted: Proxy "%1$s".', $proxy['host'])); add_audit(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_PROXY, '[' . $proxy['host'] . '] [' . $proxy['hostid'] . ']'); } return array('proxyids' => $proxyIds); }
function update_slideshow($data) { $user_data = CWebUser::$data; // Validate slides. if (empty($data['slides'])) { error(_('Slide show must contain slides.')); return false; } // validate screens. $screenids = zbx_objectValues($data['slides'], 'screenid'); $screens = API::Screen()->get(['output' => ['screenid'], 'screenids' => $screenids, 'preservekeys' => true]); foreach ($screenids as $screenid) { if (!array_key_exists($screenid, $screens)) { error(_('Incorrect screen provided for slide show.')); return false; } } // Validate slide name. $db_slideshow = DBfetch(DBselect('SELECT s.slideshowid' . ' FROM slideshows s' . ' WHERE s.name=' . zbx_dbstr($data['name']) . ' AND s.slideshowid<>' . zbx_dbstr($data['slideshowid']))); if ($db_slideshow) { error(_s('Slide show "%1$s" already exists.', $data['name'])); return false; } // Validate slide show owner. if (array_key_exists('userid', $data)) { if ($data['userid'] === null || $data['userid'] === '') { error(_('Slide show owner cannot be empty.')); return false; } elseif ($data['userid'] != $user_data['userid'] && $user_data['type'] != USER_TYPE_SUPER_ADMIN && $user_data['type'] != USER_TYPE_ZABBIX_ADMIN) { error(_('Only administrators can set slide show owner.')); return false; } } $to_update = $data; unset($to_update['slideshowid'], $to_update['slides'], $to_update['users'], $to_update['userGroups']); DB::update('slideshows', ['values' => $to_update, 'where' => ['slideshowid' => $data['slideshowid']]]); // Read-only sharing validation. foreach ($data['users'] as $user) { if ($data['private'] == PUBLIC_SHARING && $user['permission'] == PERM_READ) { error(_s('Slide show "%1$s" is public and read-only sharing is disallowed.', $data['name'])); return false; } } foreach ($data['userGroups'] as $user_group) { if ($data['private'] == PUBLIC_SHARING && $user_group['permission'] == PERM_READ) { error(_s('Slide show "%1$s" is public and read-only sharing is disallowed.', $data['name'])); return false; } } $shared_userids_to_delete = []; $shared_users_to_update = []; $shared_users_to_add = []; $shared_user_groupids_to_delete = []; $shared_user_groups_to_update = []; $shared_user_groups_to_add = []; // Slide show user shares. $db_slideshow['users'] = DBfetchArray(DBselect('SELECT s.userid,s.permission,s.slideshowuserid' . ' FROM slideshow_user s' . ' WHERE s.slideshowid=' . zbx_dbstr(getRequest('slideshowid')))); $userids = []; foreach ($db_slideshow['users'] as $user) { $userids[] = $user['userid']; } $allowed_users = API::User()->get(['output' => ['userid'], 'userids' => $userids, 'preservekeys' => true]); foreach ($db_slideshow['users'] as $key => $user) { if (!array_key_exists($user['userid'], $allowed_users)) { unset($db_slideshow['users'][$key]); } } $user_shares_diff = zbx_array_diff($data['users'], $db_slideshow['users'], 'userid'); foreach ($user_shares_diff['both'] as $update_user_share) { $shared_users_to_update[] = ['values' => $update_user_share, 'where' => ['userid' => $update_user_share['userid'], 'slideshowid' => $data['slideshowid']]]; } foreach ($user_shares_diff['first'] as $new_shared_user) { $new_shared_user['slideshowid'] = $data['slideshowid']; $shared_users_to_add[] = $new_shared_user; } $shared_userids_to_delete = zbx_objectValues($user_shares_diff['second'], 'slideshowuserid'); // Slide show user group shares. $db_slideshow['userGroups'] = DBfetchArray(DBselect('SELECT s.usrgrpid,s.permission,s.slideshowusrgrpid' . ' FROM slideshow_usrgrp s' . ' WHERE s.slideshowid=' . zbx_dbstr(getRequest('slideshowid')))); $usrgrpids = []; foreach ($db_slideshow['userGroups'] as $user_group) { $usrgrpids[] = $user_group['usrgrpid']; } $allowed_user_groups = API::UserGroup()->get(['output' => ['usrgrpid'], 'usrgrpids' => $usrgrpids, 'preservekeys' => true]); foreach ($db_slideshow['userGroups'] as $key => $user_group) { if (!array_key_exists($user_group['usrgrpid'], $allowed_user_groups)) { unset($db_slideshow['userGroups'][$key]); } } $user_group_shares_diff = zbx_array_diff($data['userGroups'], $db_slideshow['userGroups'], 'usrgrpid'); foreach ($user_group_shares_diff['both'] as $update_user_share) { $shared_user_groups_to_update[] = ['values' => $update_user_share, 'where' => ['usrgrpid' => $update_user_share['usrgrpid'], 'slideshowid' => $data['slideshowid']]]; } foreach ($user_group_shares_diff['first'] as $new_shared_user_group) { $new_shared_user_group['slideshowid'] = $data['slideshowid']; $shared_user_groups_to_add[] = $new_shared_user_group; } $shared_user_groupids_to_delete = zbx_objectValues($user_group_shares_diff['second'], 'slideshowusrgrpid'); // User shares. DB::insert('slideshow_user', $shared_users_to_add); DB::update('slideshow_user', $shared_users_to_update); if ($shared_userids_to_delete) { DB::delete('slideshow_user', ['slideshowuserid' => $shared_userids_to_delete]); } // User group shares. DB::insert('slideshow_usrgrp', $shared_user_groups_to_add); DB::update('slideshow_usrgrp', $shared_user_groups_to_update); if ($shared_user_groupids_to_delete) { DB::delete('slideshow_usrgrp', ['slideshowusrgrpid' => $shared_user_groupids_to_delete]); } // get slides $db_slides = DBfetchArrayAssoc(DBselect('SELECT s.* FROM slides s WHERE s.slideshowid=' . zbx_dbstr($data['slideshowid'])), 'slideid'); $slidesToDel = zbx_objectValues($db_slides, 'slideid'); $slidesToDel = zbx_toHash($slidesToDel); $step = 0; foreach ($data['slides'] as $slide) { $slide['delay'] = $slide['delay'] ? $slide['delay'] : 0; if (isset($db_slides[$slide['slideid']])) { // update slide if ($db_slides[$slide['slideid']]['delay'] != $slide['delay'] || $db_slides[$slide['slideid']]['step'] != $step) { $result = DBexecute('UPDATE slides SET step=' . zbx_dbstr($step) . ', delay=' . zbx_dbstr($slide['delay']) . ' WHERE slideid=' . zbx_dbstr($slide['slideid'])); } else { $result = true; } unset($slidesToDel[$slide['slideid']]); } else { $slideid = get_dbid('slides', 'slideid'); $result = DBexecute('INSERT INTO slides (slideid,slideshowid,screenid,step,delay)' . ' VALUES (' . zbx_dbstr($slideid) . ',' . zbx_dbstr($data['slideshowid']) . ',' . zbx_dbstr($slide['screenid']) . ',' . zbx_dbstr($step) . ',' . zbx_dbstr($slide['delay']) . ')'); } $step++; if (!$result) { return false; } } // delete unnecessary slides if (!empty($slidesToDel)) { DBexecute('DELETE FROM slides WHERE slideid IN(' . implode(',', $slidesToDel) . ')'); } return true; }
$severity[$i] = $i; } } } else { $severity = get_request('severity', array(0, 1, 2, 3, 4, 5)); } $media = get_request('media', -1); $sendto = get_request('sendto', ''); $mediatypeid = get_request('mediatypeid', 0); $active = get_request('active', 0); $period = get_request('period', ZBX_DEFAULT_INTERVAL); $frmMedia = new CFormTable(_('New media')); $frmMedia->addVar('media', $media); $frmMedia->addVar('dstfrm', $_REQUEST['dstfrm']); $cmbType = new CComboBox('mediatypeid', $mediatypeid); $types = DBfetchArrayAssoc(DBselect('SELECT mt.mediatypeid,mt.description' . ' FROM media_type mt' . whereDbNode('mt.mediatypeid')), 'mediatypeid'); CArrayHelper::sort($types, array('description')); foreach ($types as $mediaTypeId => $type) { $cmbType->addItem($mediaTypeId, get_node_name_by_elid($type['mediatypeid'], null, NAME_DELIMITER) . $type['description']); } $frmMedia->addRow(_('Type'), $cmbType); $frmMedia->addRow(_('Send to'), new CTextBox('sendto', $sendto, 48)); $frmMedia->addRow(_('When active'), new CTextBox('period', $period, 48)); $frm_row = array(); foreach (getSeverityCaption() as $i => $caption) { $frm_row[] = array(new CCheckBox('severity[' . $i . ']', str_in_array($i, $severity), null, $i), $caption); $frm_row[] = BR(); } $frmMedia->addRow(_('Use if severity'), $frm_row); $cmbStat = new CComboBox('active', $active); $cmbStat->addItem(0, _('Enabled'));
protected function applyPostSqlFiltering(array $triggers, array $options) { $triggers = zbx_toHash($triggers, 'triggerid'); // skipDependent if (!is_null($options['skipDependent'])) { $triggerIds = zbx_objectValues($triggers, 'triggerid'); $map = array(); do { $dbResult = DBselect('SELECT d.triggerid_down,d.triggerid_up,t.value' . ' FROM trigger_depends d,triggers t' . ' WHERE ' . dbConditionInt('d.triggerid_down', $triggerIds) . ' AND d.triggerid_up=t.triggerid'); $triggerIds = array(); while ($row = DBfetch($dbResult)) { if (TRIGGER_VALUE_TRUE == $row['value']) { if (isset($map[$row['triggerid_down']])) { foreach ($map[$row['triggerid_down']] as $triggerid => $state) { unset($triggers[$triggerid]); } } else { unset($triggers[$row['triggerid_down']]); } } else { if (isset($map[$row['triggerid_down']])) { if (!isset($map[$row['triggerid_up']])) { $map[$row['triggerid_up']] = array(); } $map[$row['triggerid_up']] += $map[$row['triggerid_down']]; } else { if (!isset($map[$row['triggerid_up']])) { $map[$row['triggerid_up']] = array(); } $map[$row['triggerid_up']][$row['triggerid_down']] = 1; } $triggerIds[] = $row['triggerid_up']; } } } while (!empty($triggerIds)); } // withLastEventUnacknowledged if (!is_null($options['withLastEventUnacknowledged'])) { $triggerIds = zbx_objectValues($triggers, 'triggerid'); $eventIds = array(); $eventsDb = DBselect('SELECT MAX(e.eventid) AS eventid,e.objectid' . ' FROM events e' . ' WHERE e.object=' . EVENT_OBJECT_TRIGGER . ' AND e.source=' . EVENT_SOURCE_TRIGGERS . ' AND ' . dbConditionInt('e.objectid', $triggerIds) . ' AND ' . dbConditionInt('e.value', array(TRIGGER_VALUE_TRUE)) . ' GROUP BY e.objectid'); while ($event = DBfetch($eventsDb)) { $eventIds[] = $event['eventid']; } $correctTriggerIds = DBfetchArrayAssoc(DBselect('SELECT e.objectid' . ' FROM events e ' . ' WHERE ' . dbConditionInt('e.eventid', $eventIds) . ' AND e.acknowledged=0'), 'objectid'); foreach ($triggers as $triggerId => $trigger) { if (!isset($correctTriggerIds[$triggerId])) { unset($triggers[$triggerId]); } } } return $triggers; }
// get items $data['hostPrototypes'] = API::HostPrototype()->get(array('discoveryids' => $data['parent_discoveryid'], 'output' => API_OUTPUT_EXTEND, 'selectTemplates' => array('templateid', 'name'), 'editable' => true, 'sortfield' => $sortField, 'limit' => $config['search_limit'] + 1)); order_result($data['hostPrototypes'], $sortField, $sortOrder); $data['paging'] = getPagingLine($data['hostPrototypes'], $sortOrder); // fetch templates linked to the prototypes $templateIds = array(); foreach ($data['hostPrototypes'] as $hostPrototype) { $templateIds = array_merge($templateIds, zbx_objectValues($hostPrototype['templates'], 'templateid')); } $templateIds = array_unique($templateIds); $linkedTemplates = API::Template()->get(array('output' => array('templateid', 'name'), 'templateids' => $templateIds, 'selectParentTemplates' => array('hostid', 'name'))); $data['linkedTemplates'] = zbx_toHash($linkedTemplates, 'templateid'); // fetch source templates and LLD rules $hostPrototypeSourceIds = getHostPrototypeSourceParentIds(zbx_objectValues($data['hostPrototypes'], 'hostid')); if ($hostPrototypeSourceIds) { $hostPrototypeSourceTemplates = DBfetchArrayAssoc(DBSelect('SELECT h.hostid,h2.name,h2.hostid AS parent_hostid' . ' FROM hosts h,host_discovery hd,items i,hosts h2' . ' WHERE h.hostid=hd.hostid' . ' AND hd.parent_itemid=i.itemid' . ' AND i.hostid=h2.hostid' . ' AND ' . dbConditionInt('h.hostid', $hostPrototypeSourceIds)), 'hostid'); foreach ($data['hostPrototypes'] as &$hostPrototype) { if ($hostPrototype['templateid']) { $sourceTemplate = $hostPrototypeSourceTemplates[$hostPrototypeSourceIds[$hostPrototype['hostid']]]; $hostPrototype['sourceTemplate'] = array('hostid' => $sourceTemplate['parent_hostid'], 'name' => $sourceTemplate['name']); $sourceDiscoveryRuleId = get_realrule_by_itemid_and_hostid($discoveryRule['itemid'], $sourceTemplate['hostid']); $hostPrototype['sourceDiscoveryRuleId'] = $sourceDiscoveryRuleId; } } unset($hostPrototype); } // render view $itemView = new CView('configuration.host.prototype.list', $data); $itemView->render(); $itemView->show(); }
/** * Update web scenario steps. * * @param $httpTest * @param $websteps * * @throws Exception */ protected function updateStepsReal($httpTest, $websteps) { // get all used keys $webstepids = zbx_objectValues($websteps, 'httpstepid'); $dbKeys = DBfetchArrayAssoc(DBselect('SELECT i.key_' . ' FROM items i,httpstepitem hi' . ' WHERE ' . dbConditionInt('hi.httpstepid', $webstepids) . ' AND hi.itemid=i.itemid'), 'key_'); foreach ($websteps as $webstep) { DB::update('httpstep', array('values' => $webstep, 'where' => array('httpstepid' => $webstep['httpstepid']))); // update item keys $itemids = array(); $stepitemsUpdate = $updateFields = array(); $dbStepItems = DBselect('SELECT i.itemid,i.key_,hi.type' . ' FROM items i,httpstepitem hi' . ' WHERE hi.httpstepid=' . zbx_dbstr($webstep['httpstepid']) . ' AND hi.itemid=i.itemid'); while ($stepitem = DBfetch($dbStepItems)) { $itemids[] = $stepitem['itemid']; if (isset($httpTest['name']) || isset($webstep['name'])) { if (!isset($httpTest['name']) || !isset($webstep['name'])) { $key = new CItemKey($stepitem['key_']); $params = $key->getParameters(); if (!isset($httpTest['name'])) { $httpTest['name'] = $params[0]; } if (!isset($webstep['name'])) { $webstep['name'] = $params[1]; } } $updateFields['key_'] = $this->getStepKey($stepitem['type'], $httpTest['name'], $webstep['name']); } if (isset($dbKeys[$updateFields['key_']])) { unset($updateFields['key_']); } if (isset($httpTest['status'])) { $updateFields['status'] = HTTPTEST_STATUS_ACTIVE == $httpTest['status'] ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED; } if (isset($httpTest['delay'])) { $updateFields['delay'] = $httpTest['delay']; } if (!empty($updateFields)) { $stepitemsUpdate[] = array('values' => $updateFields, 'where' => array('itemid' => $stepitem['itemid'])); } } DB::update('items', $stepitemsUpdate); if (isset($httpTest['applicationid'])) { $this->updateItemsApplications($itemids, $httpTest['applicationid']); } } }
$severity[$i] = $i; } } } else { $severity = getRequest('severity', array(0, 1, 2, 3, 4, 5)); } $media = getRequest('media', -1); $sendto = getRequest('sendto', ''); $mediatypeid = getRequest('mediatypeid', 0); $active = getRequest('active', 0); $period = getRequest('period', ZBX_DEFAULT_INTERVAL); $frmMedia = new CFormTable(_('New media')); $frmMedia->addVar('media', $media); $frmMedia->addVar('dstfrm', $_REQUEST['dstfrm']); $cmbType = new CComboBox('mediatypeid', $mediatypeid); $types = DBfetchArrayAssoc(DBselect('SELECT mt.mediatypeid,mt.description FROM media_type mt'), 'mediatypeid'); CArrayHelper::sort($types, array('description')); foreach ($types as $mediaTypeId => $type) { $cmbType->addItem($mediaTypeId, $type['description']); } $frmMedia->addRow(_('Type'), $cmbType); $frmMedia->addRow(_('Send to'), new CTextBox('sendto', $sendto, 48)); $frmMedia->addRow(_('When active'), new CTextBox('period', $period, 48)); $frm_row = array(); foreach (getSeverityCaption() as $i => $caption) { $frm_row[] = array(new CCheckBox('severity[' . $i . ']', str_in_array($i, $severity), null, $i), $caption); $frm_row[] = BR(); } $frmMedia->addRow(_('Use if severity'), $frm_row); $cmbStat = new CComboBox('active', $active); $cmbStat->addItem(0, _('Enabled'));
/** * Creates the availability report page filter and modifies trigger retrieval options. * * Possible $config values are AVAILABILITY_REPORT_BY_HOST or AVAILABILITY_REPORT_BY_TEMPLATE. * * @param int $config report mode * @param array $PAGE_GROUPS the data for the host/template group filter select * @param array $PAGE_HOSTS the data for the host/template filter select * @param array $options trigger retrieval options, to be modified * * @return array returns form table and modified options: array('form' => CFormTable, 'options' => array) */ function get_report2_filter($config, array $PAGE_GROUPS, array $PAGE_HOSTS, $options) { $filterForm = new CFormTable(); $filterForm->setAttribute('name', 'zbx_filter'); $filterForm->setAttribute('id', 'zbx_filter'); $filterForm->addVar('config', $config); $filterForm->addVar('filter_timesince', date('YmdHis', $_REQUEST['filter_timesince'])); $filterForm->addVar('filter_timetill', date('YmdHis', $_REQUEST['filter_timetill'])); $cmbGroups = new CComboBox('filter_groupid', $PAGE_GROUPS['selected'], 'javascript: submit();'); $cmbHosts = new CComboBox('filter_hostid', $PAGE_HOSTS['selected'], 'javascript: submit();'); foreach ($PAGE_GROUPS['groups'] as $groupid => $name) { $cmbGroups->addItem($groupid, get_node_name_by_elid($groupid, null, ': ') . $name); } foreach ($PAGE_HOSTS['hosts'] as $hostid => $name) { $cmbHosts->addItem($hostid, get_node_name_by_elid($hostid, null, ': ') . $name); } if ($config == AVAILABILITY_REPORT_BY_TEMPLATE) { $filterForm->addRow(_('Template group'), $cmbGroups); $filterForm->addRow(_('Template'), $cmbHosts); $cmbTrigs = new CComboBox('tpl_triggerid', get_request('tpl_triggerid', 0), 'submit()'); $cmbHGrps = new CComboBox('hostgroupid', get_request('hostgroupid', 0), 'submit()'); $cmbTrigs->addItem(0, _('all')); $cmbHGrps->addItem(0, _('all')); // fetch the groups, that the used hosts belong to $hostGroups = API::HostGroup()->get(array('output' => array('name', 'groupid'), 'hostids' => $options['hostids'], 'monitored_hosts' => true, 'preservekeys' => true)); foreach ($hostGroups as $hostGroup) { $cmbHGrps->addItem($hostGroup['groupid'], get_node_name_by_elid($hostGroup['groupid'], null, ': ') . $hostGroup['name']); } if (isset($_REQUEST['hostgroupid']) && !isset($hostGroups[$_REQUEST['hostgroupid']])) { unset($options['groupids']); } if ($PAGE_HOSTS['selected']) { $sql_cond = ' AND h.hostid=' . $PAGE_HOSTS['selected']; } else { $sql_cond = ' AND ' . dbConditionInt('h.hostid', $PAGE_HOSTS['hostids']); } $sql = 'SELECT DISTINCT t.triggerid,t.description ' . ' FROM triggers t,hosts h,items i,functions f ' . ' WHERE f.itemid=i.itemid ' . ' AND h.hostid=i.hostid ' . ' AND t.status=' . TRIGGER_STATUS_ENABLED . ' AND t.triggerid=f.triggerid ' . ' AND h.status=' . HOST_STATUS_TEMPLATE . ' AND ' . DBin_node('t.triggerid') . ' AND i.status=' . ITEM_STATUS_ACTIVE . $sql_cond . ' ORDER BY t.description'; $triggers = DBfetchArrayAssoc(DBselect($sql), 'triggerid'); foreach ($triggers as $trigger) { $cmbTrigs->addItem($trigger['triggerid'], get_node_name_by_elid($trigger['triggerid'], null, ': ') . $trigger['description']); } if (isset($_REQUEST['tpl_triggerid']) && !isset($triggers[$_REQUEST['tpl_triggerid']])) { unset($options['filter']['templateid']); } $filterForm->addRow(_('Template trigger'), $cmbTrigs); $filterForm->addRow(_('Filter by host group'), $cmbHGrps); } elseif ($config == AVAILABILITY_REPORT_BY_HOST) { $filterForm->addRow(_('Host group'), $cmbGroups); $filterForm->addRow(_('Host'), $cmbHosts); } //* $clndr_icon = new CImg('images/general/bar/cal.gif', 'calendar', 16, 12, 'pointer'); $clndr_icon->addAction('onclick', 'javascript: ' . 'var pos = getPosition(this); ' . 'pos.top+=10; ' . 'pos.left+=16; ' . "CLNDR['avail_report_since'].clndr.clndrshow(pos.top,pos.left);"); $filtertimetab = new CTable(null, 'calendar'); $filtertimetab->setAttribute('width', '10%'); $filtertimetab->setCellPadding(0); $filtertimetab->setCellSpacing(0); $filtertimetab->addRow(array(_('From'), new CNumericBox('filter_since_day', $_REQUEST['filter_timesince'] > 0 ? date('d', $_REQUEST['filter_timesince']) : '', 2), '/', new CNumericBox('filter_since_month', $_REQUEST['filter_timesince'] > 0 ? date('m', $_REQUEST['filter_timesince']) : '', 2), '/', new CNumericBox('filter_since_year', $_REQUEST['filter_timesince'] > 0 ? date('Y', $_REQUEST['filter_timesince']) : '', 4), SPACE, new CNumericBox('filter_since_hour', $_REQUEST['filter_timesince'] > 0 ? date('H', $_REQUEST['filter_timesince']) : '', 2), ':', new CNumericBox('filter_since_minute', $_REQUEST['filter_timesince'] > 0 ? date('i', $_REQUEST['filter_timesince']) : '', 2), $clndr_icon)); zbx_add_post_js('create_calendar(null,' . '["filter_since_day","filter_since_month","filter_since_year","filter_since_hour","filter_since_minute"],' . '"avail_report_since",' . '"filter_timesince");'); $clndr_icon->AddAction('onclick', 'javascript: ' . 'var pos = getPosition(this); ' . 'pos.top+=10; ' . 'pos.left+=16; ' . "CLNDR['avail_report_till'].clndr.clndrshow(pos.top,pos.left);"); $filtertimetab->AddRow(array(_('Till'), new CNumericBox('filter_till_day', $_REQUEST['filter_timetill'] > 0 ? date('d', $_REQUEST['filter_timetill']) : '', 2), '/', new CNumericBox('filter_till_month', $_REQUEST['filter_timetill'] > 0 ? date('m', $_REQUEST['filter_timetill']) : '', 2), '/', new CNumericBox('filter_till_year', $_REQUEST['filter_timetill'] > 0 ? date('Y', $_REQUEST['filter_timetill']) : '', 4), SPACE, new CNumericBox('filter_till_hour', $_REQUEST['filter_timetill'] > 0 ? date('H', $_REQUEST['filter_timetill']) : '', 2), ':', new CNumericBox('filter_till_minute', $_REQUEST['filter_timetill'] > 0 ? date('i', $_REQUEST['filter_timetill']) : '', 2), $clndr_icon)); zbx_add_post_js('create_calendar(null,' . '["filter_till_day","filter_till_month","filter_till_year","filter_till_hour","filter_till_minute"],' . '"avail_report_till",' . '"filter_timetill");'); zbx_add_post_js('addListener($("filter_icon"),"click",CLNDR[\'avail_report_since\'].clndr.clndrhide.bindAsEventListener(CLNDR[\'avail_report_since\'].clndr));' . 'addListener($("filter_icon"),"click",CLNDR[\'avail_report_till\'].clndr.clndrhide.bindAsEventListener(CLNDR[\'avail_report_till\'].clndr));'); $filterForm->addRow(_('Period'), $filtertimetab); //*/ $filterForm->addItemToBottomRow(new CSubmit('filter_set', _('Filter'))); $reset = new CButton("filter_rst", _('Reset'), 'javascript: var url = new Curl(location.href); url.setArgument("filter_rst",1); location.href = url.getUrl();'); $filterForm->addItemToBottomRow($reset); return array('form' => $filterForm, 'options' => $options); }
/** * Mass update hosts. * * @param array $hosts multidimensional array with Hosts data * @param array $hosts['hosts'] Array of Host objects to update * @param string $hosts['fields']['host'] Host name. * @param array $hosts['fields']['groupids'] HostGroup IDs add Host to. * @param int $hosts['fields']['port'] Port. OPTIONAL * @param int $hosts['fields']['status'] Host Status. OPTIONAL * @param int $hosts['fields']['useip'] Use IP. OPTIONAL * @param string $hosts['fields']['dns'] DNS. OPTIONAL * @param string $hosts['fields']['ip'] IP. OPTIONAL * @param int $hosts['fields']['proxy_hostid'] Proxy Host ID. OPTIONAL * @param int $hosts['fields']['ipmi_authtype'] IPMI authentication type. OPTIONAL * @param int $hosts['fields']['ipmi_privilege'] IPMI privilege. OPTIONAL * @param string $hosts['fields']['ipmi_username'] IPMI username. OPTIONAL * @param string $hosts['fields']['ipmi_password'] IPMI password. OPTIONAL * * @return boolean */ public function massUpdate($data) { $hosts = zbx_toArray($data['hosts']); $inputHostIds = zbx_objectValues($hosts, 'hostid'); $hostids = array_unique($inputHostIds); sort($hostids); $updHosts = $this->get(array('hostids' => $hostids, 'editable' => true, 'output' => API_OUTPUT_EXTEND, 'preservekeys' => true)); foreach ($hosts as $host) { if (!isset($updHosts[$host['hostid']])) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); } } // check if hosts have at least 1 group if (isset($data['groups']) && empty($data['groups'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No groups for hosts.')); } /* * Update hosts properties */ if (isset($data['name'])) { if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update visible host name.')); } } if (isset($data['host'])) { if (!preg_match('/^' . ZBX_PREG_HOST_FORMAT . '$/', $data['host'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect characters used for host name "%s".', $data['host'])); } if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update host name.')); } $curHost = reset($hosts); $hostExists = $this->get(array('filter' => array('host' => $curHost['host']), 'output' => array('hostid'), 'editable' => true, 'nopermissions' => true)); $hostExist = reset($hostExists); if ($hostExist && bccomp($hostExist['hostid'], $curHost['hostid']) != 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Host "%1$s" already exists.', $data['host'])); } // can't add host with the same name as existing template if (API::Template()->exists(array('host' => $curHost['host']))) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Template "%1$s" already exists.', $curHost['host'])); } } if (isset($data['groups'])) { $updateGroups = $data['groups']; } if (isset($data['interfaces'])) { $updateInterfaces = $data['interfaces']; } if (isset($data['templates_clear'])) { $updateTemplatesClear = zbx_toArray($data['templates_clear']); } if (isset($data['templates'])) { $updateTemplates = $data['templates']; } if (isset($data['macros'])) { $updateMacros = $data['macros']; } // second check is necessary, because import incorrectly inputs unset 'inventory' as empty string rather than null if (isset($data['inventory']) && $data['inventory']) { $updateInventory = $data['inventory']; $updateInventory['inventory_mode'] = null; if (isset($data['inventory_mode']) && $data['inventory_mode'] == HOST_INVENTORY_DISABLED) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot set inventory fields for disabled inventory.')); } } if (isset($data['inventory_mode'])) { if (!isset($updateInventory)) { $updateInventory = array(); } $updateInventory['inventory_mode'] = $data['inventory_mode']; } if (isset($data['status'])) { $updateStatus = $data['status']; } unset($data['hosts'], $data['groups'], $data['interfaces'], $data['templates_clear'], $data['templates'], $data['macros'], $data['inventory'], $data['inventory_mode'], $data['status']); if (!zbx_empty($data)) { DB::update('hosts', array('values' => $data, 'where' => array('hostid' => $hostids))); } if (isset($updateStatus)) { updateHostStatus($hostids, $updateStatus); } /* * Update hostgroups linkage */ if (isset($updateGroups)) { $updateGroups = zbx_toArray($updateGroups); $hostGroups = API::HostGroup()->get(array('hostids' => $hostids)); $hostGroupids = zbx_objectValues($hostGroups, 'groupid'); $newGroupids = zbx_objectValues($updateGroups, 'groupid'); $result = $this->massAdd(array('hosts' => $hosts, 'groups' => $updateGroups)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot create host group.')); } $groupidsToDel = array_diff($hostGroupids, $newGroupids); if ($groupidsToDel) { $result = $this->massRemove(array('hostids' => $hostids, 'groupids' => $groupidsToDel)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete host group.')); } } } /* * Update interfaces */ if (isset($updateInterfaces)) { $hostInterfaces = API::HostInterface()->get(array('hostids' => $hostids, 'output' => API_OUTPUT_EXTEND, 'preservekeys' => true, 'nopermissions' => true)); $this->massRemove(array('hostids' => $hostids, 'interfaces' => $hostInterfaces)); $this->massAdd(array('hosts' => $hosts, 'interfaces' => $updateInterfaces)); } if (isset($updateTemplatesClear)) { $templateidsClear = zbx_objectValues($updateTemplatesClear, 'templateid'); if ($updateTemplatesClear) { $this->massRemove(array('hostids' => $hostids, 'templateids_clear' => $templateidsClear)); } } else { $templateidsClear = array(); } /* * Update template linkage */ if (isset($updateTemplates)) { $hostTemplates = API::Template()->get(array('hostids' => $hostids, 'output' => array('templateid'), 'preservekeys' => true)); $hostTemplateids = array_keys($hostTemplates); $newTemplateids = zbx_objectValues($updateTemplates, 'templateid'); $templatesToDel = array_diff($hostTemplateids, $newTemplateids); $templatesToDel = array_diff($templatesToDel, $templateidsClear); if ($templatesToDel) { $result = $this->massRemove(array('hostids' => $hostids, 'templateids' => $templatesToDel)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot unlink template')); } } $result = $this->massAdd(array('hosts' => $hosts, 'templates' => $updateTemplates)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot link template')); } } // macros if (isset($updateMacros)) { DB::delete('hostmacro', array('hostid' => $hostids)); $this->massAdd(array('hosts' => $hosts, 'macros' => $updateMacros)); } /* * Inventory */ if (isset($updateInventory)) { if ($updateInventory['inventory_mode'] == HOST_INVENTORY_DISABLED) { $sql = 'DELETE FROM host_inventory WHERE ' . dbConditionInt('hostid', $hostids); if (!DBexecute($sql)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete inventory.')); } } else { $hostsWithInventories = array(); $existingInventoriesDb = DBfetchArrayAssoc(DBselect('SELECT hostid' . ' FROM host_inventory' . ' WHERE ' . dbConditionInt('hostid', $hostids)), 'hostid'); // check for hosts with disabled inventory mode if ($updateInventory['inventory_mode'] === null && count($existingInventoriesDb) !== count($hostids)) { foreach ($hostids as $hostId) { if (!isset($existingInventoriesDb[$hostId])) { $host = get_host_by_hostid($hostId); self::exception(ZBX_API_ERROR_PARAMETERS, _s('Inventory disabled for host "%s".', $host['host'])); } } } foreach ($existingInventoriesDb as $existingInventory) { $hostsWithInventories[] = $existingInventory['hostid']; } // when hosts are being updated to use automatic mode for host inventories, // we must check if some items are set to populate inventory fields of every host. // if they do, mass update for those fields should be ignored if ($updateInventory['inventory_mode'] == HOST_INVENTORY_AUTOMATIC) { // getting all items on all affected hosts $itemsToInventories = API::item()->get(array('output' => array('inventory_link', 'hostid'), 'filter' => array('hostid' => $hostids), 'nopermissions' => true)); // gathering links to array: 'hostid'=>array('inventory_name_1'=>true, 'inventory_name_2'=>true) $inventoryLinksOnHosts = array(); $inventoryFields = getHostInventories(); foreach ($itemsToInventories as $hinv) { if ($hinv['inventory_link'] != 0) { // 0 means 'no link' if (isset($inventoryLinksOnHosts[$hinv['hostid']])) { $inventoryLinksOnHosts[$hinv['hostid']][$inventoryFields[$hinv['inventory_link']]['db_field']] = true; } else { $inventoryLinksOnHosts[$hinv['hostid']] = array($inventoryFields[$hinv['inventory_link']]['db_field'] => true); } } } // now we have all info we need to determine, which inventory fields should be saved $inventoriesToSave = array(); foreach ($hostids as $hostid) { $inventoriesToSave[$hostid] = $updateInventory; $inventoriesToSave[$hostid]['hostid'] = $hostid; foreach ($updateInventory as $inventoryName => $hinv) { if (isset($inventoryLinksOnHosts[$hostid][$inventoryName])) { unset($inventoriesToSave[$hostid][$inventoryName]); } } } } else { // if mode is not automatic, all fields can be saved $inventoriesToSave = array(); foreach ($hostids as $hostid) { $inventoriesToSave[$hostid] = $updateInventory; $inventoriesToSave[$hostid]['hostid'] = $hostid; } } $hostsWithoutInventory = array_diff($hostids, $hostsWithInventories); // hosts that have no inventory yet, need it to be inserted foreach ($hostsWithoutInventory as $hostid) { DB::insert('host_inventory', array($inventoriesToSave[$hostid]), false); } // those hosts that already have an inventory, need it to be updated foreach ($hostsWithInventories as $hostid) { DB::update('host_inventory', array('values' => $inventoriesToSave[$hostid], 'where' => array('hostid' => $hostid))); } } } return array('hostids' => $inputHostIds); }
function update_slideshow($slideshowid, $name, $delay, $slides) { // validate slides if (empty($slides)) { error(_('Slide show must contain slides.')); return false; } // validate screens $screenids = zbx_objectValues($slides, 'screenid'); $screens = API::Screen()->get(array('screenids' => $screenids, 'output' => array('screenid'))); $screens = ZBX_toHash($screens, 'screenid'); foreach ($screenids as $screenid) { if (!isset($screens[$screenid])) { error(_('Incorrect screen provided for slide show.')); return false; } } // validate slide name $db_slideshow = DBfetch(DBselect('SELECT s.slideshowid' . ' FROM slideshows s' . ' WHERE s.name=' . zbx_dbstr($name) . ' AND s.slideshowid<>' . zbx_dbstr($slideshowid) . ' ' . andDbNode('s.slideshowid'))); if (!empty($db_slideshow)) { error(_s('Slide show "%s" already exists.', $name)); return false; } $db_slideshow = DBfetchArray(DBselect('SELECT * FROM slideshows WHERE slideshowid=' . zbx_dbstr($slideshowid))); $db_slideshow = $db_slideshow[0]; $changed = false; $slideshow = array('name' => $name, 'delay' => $delay); foreach ($slideshow as $key => $val) { if ($db_slideshow[$key] != $val) { $changed = true; break; } } if ($changed) { if (!($result = DBexecute('UPDATE slideshows SET name=' . zbx_dbstr($name) . ',delay=' . zbx_dbstr($delay) . ' WHERE slideshowid=' . zbx_dbstr($slideshowid)))) { return false; } } // get slides $db_slides = DBfetchArrayAssoc(DBselect('SELECT s.* FROM slides s WHERE s.slideshowid=' . zbx_dbstr($slideshowid)), 'slideid'); $slidesToDel = zbx_objectValues($db_slides, 'slideid'); $slidesToDel = zbx_toHash($slidesToDel); $step = 0; foreach ($slides as $slide) { $slide['delay'] = $slide['delay'] ? $slide['delay'] : 0; if (isset($db_slides[$slide['slideid']])) { // update slide if ($db_slides[$slide['slideid']]['delay'] != $slide['delay'] || $db_slides[$slide['slideid']]['step'] != $step) { $result = DBexecute('UPDATE slides SET step=' . zbx_dbstr($step) . ', delay=' . zbx_dbstr($slide['delay']) . ' WHERE slideid=' . zbx_dbstr($slide['slideid'])); } else { $result = true; } unset($slidesToDel[$slide['slideid']]); } else { $slideid = get_dbid('slides', 'slideid'); $result = DBexecute('INSERT INTO slides (slideid,slideshowid,screenid,step,delay)' . ' VALUES (' . zbx_dbstr($slideid) . ',' . zbx_dbstr($slideshowid) . ',' . zbx_dbstr($slide['screenid']) . ',' . zbx_dbstr($step) . ',' . zbx_dbstr($slide['delay']) . ')'); } $step++; if (!$result) { return false; } } // delete unnecessary slides if (!empty($slidesToDel)) { DBexecute('DELETE FROM slides WHERE slideid IN(' . implode(',', $slidesToDel) . ')'); } return true; }
$templateComboBox = new CComboBox('filter_hostid', $_REQUEST['filter_hostid'], 'javascript: submit();'); $templateComboBox->addItem(0, _('all')); $templates = API::Template()->get(array('output' => array('templateid', 'name'), 'groupids' => empty($_REQUEST['filter_groupid']) ? null : $_REQUEST['filter_groupid'], 'with_triggers' => true)); order_result($templates, 'name'); $templateIds = array(); foreach ($templates as $template) { $templateIds[$template['templateid']] = $template['templateid']; $templateComboBox->addItem($template['templateid'], $template['name']); } $filterForm->addRow(_('Template'), $templateComboBox); // filter trigger $triggerComboBox = new CComboBox('tpl_triggerid', getRequest('tpl_triggerid', 0), 'javascript: submit()'); $triggerComboBox->addItem(0, _('all')); $sqlCondition = empty($_REQUEST['filter_hostid']) ? ' AND ' . dbConditionInt('h.hostid', $templateIds) : ' AND h.hostid=' . zbx_dbstr($_REQUEST['filter_hostid']); $sql = 'SELECT DISTINCT t.triggerid,t.description,h.name' . ' FROM triggers t,hosts h,items i,functions f' . ' WHERE f.itemid=i.itemid' . ' AND h.hostid=i.hostid' . ' AND t.status=' . TRIGGER_STATUS_ENABLED . ' AND t.triggerid=f.triggerid' . ' AND h.status=' . HOST_STATUS_TEMPLATE . ' AND i.status=' . ITEM_STATUS_ACTIVE . $sqlCondition . ' ORDER BY t.description'; $triggers = DBfetchArrayAssoc(DBselect($sql), 'triggerid'); foreach ($triggers as $trigger) { $templateName = empty($_REQUEST['filter_hostid']) ? $trigger['name'] . NAME_DELIMITER : ''; $triggerComboBox->addItem($trigger['triggerid'], $templateName . $trigger['description']); } if (isset($_REQUEST['tpl_triggerid']) && !isset($triggers[$_REQUEST['tpl_triggerid']])) { unset($triggerOptions['filter']['templateid']); } $filterForm->addRow(_('Template trigger'), $triggerComboBox); // filter host group $hostGroupsComboBox = new CComboBox('hostgroupid', getRequest('hostgroupid', 0), 'javascript: submit()'); $hostGroupsComboBox->addItem(0, _('all')); $hostGroups = API::HostGroup()->get(array('output' => array('groupid', 'name'), 'hostids' => $triggerOptions['hostids'], 'monitored_hosts' => true, 'preservekeys' => true)); order_result($hostGroups, 'name'); foreach ($hostGroups as $hostGroup) { $hostGroupsComboBox->addItem($hostGroup['groupid'], $hostGroup['name']);
/** * Mass update hosts. * * @param array $hosts multidimensional array with Hosts data * @param array $hosts['hosts'] Array of Host objects to update * @param string $hosts['fields']['host'] Host name. * @param array $hosts['fields']['groupids'] HostGroup IDs add Host to. * @param int $hosts['fields']['port'] Port. OPTIONAL * @param int $hosts['fields']['status'] Host Status. OPTIONAL * @param int $hosts['fields']['useip'] Use IP. OPTIONAL * @param string $hosts['fields']['dns'] DNS. OPTIONAL * @param string $hosts['fields']['ip'] IP. OPTIONAL * @param int $hosts['fields']['bulk'] bulk. OPTIONAL * @param int $hosts['fields']['proxy_hostid'] Proxy Host ID. OPTIONAL * @param int $hosts['fields']['ipmi_authtype'] IPMI authentication type. OPTIONAL * @param int $hosts['fields']['ipmi_privilege'] IPMI privilege. OPTIONAL * @param string $hosts['fields']['ipmi_username'] IPMI username. OPTIONAL * @param string $hosts['fields']['ipmi_password'] IPMI password. OPTIONAL * * @return boolean */ public function massUpdate($data) { $hosts = zbx_toArray($data['hosts']); $inputHostIds = zbx_objectValues($hosts, 'hostid'); $hostids = array_unique($inputHostIds); sort($hostids); $db_hosts = $this->get(['output' => ['hostid', 'tls_connect', 'tls_accept', 'tls_issuer', 'tls_subject', 'tls_psk_identity', 'tls_psk'], 'hostids' => $hostids, 'editable' => true, 'preservekeys' => true]); foreach ($hosts as $host) { if (!array_key_exists($host['hostid'], $db_hosts)) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); } } // Check connection fields only for massupdate action. if ((array_key_exists('tls_connect', $data) || array_key_exists('tls_accept', $data) || array_key_exists('tls_psk_identity', $data) || array_key_exists('tls_psk', $data) || array_key_exists('tls_issuer', $data) || array_key_exists('tls_subject', $data)) && (!array_key_exists('tls_connect', $data) || !array_key_exists('tls_accept', $data))) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('Cannot update host encryption settings. Connection settings for both directions should be specified.')); } $this->validateEncryption([$data]); // Clean PSK fields. if (array_key_exists('tls_connect', $data) && $data['tls_connect'] != HOST_ENCRYPTION_PSK && (array_key_exists('tls_accept', $data) && ($data['tls_accept'] & HOST_ENCRYPTION_PSK) != HOST_ENCRYPTION_PSK)) { $data['tls_psk_identity'] = ''; $data['tls_psk'] = ''; } // Clean certificate fields. if (array_key_exists('tls_connect', $data) && $data['tls_connect'] != HOST_ENCRYPTION_CERTIFICATE && (array_key_exists('tls_accept', $data) && ($data['tls_accept'] & HOST_ENCRYPTION_CERTIFICATE) != HOST_ENCRYPTION_CERTIFICATE)) { $data['tls_issuer'] = ''; $data['tls_subject'] = ''; } // check if hosts have at least 1 group if (isset($data['groups']) && empty($data['groups'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No groups for hosts.')); } /* * Update hosts properties */ if (isset($data['name'])) { if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update visible host name.')); } } if (isset($data['host'])) { if (!preg_match('/^' . ZBX_PREG_HOST_FORMAT . '$/', $data['host'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect characters used for host name "%s".', $data['host'])); } if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update host name.')); } $curHost = reset($hosts); $sameHostnameHost = $this->get(['output' => ['hostid'], 'filter' => ['host' => $data['host']], 'nopermissions' => true, 'limit' => 1]); $sameHostnameHost = reset($sameHostnameHost); if ($sameHostnameHost && bccomp($sameHostnameHost['hostid'], $curHost['hostid']) != 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Host "%1$s" already exists.', $data['host'])); } // can't add host with the same name as existing template $sameHostnameTemplate = API::Template()->get(['output' => ['templateid'], 'filter' => ['host' => $data['host']], 'nopermissions' => true, 'limit' => 1]); if ($sameHostnameTemplate) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Template "%1$s" already exists.', $data['host'])); } } if (isset($data['groups'])) { $updateGroups = $data['groups']; } if (isset($data['interfaces'])) { $updateInterfaces = $data['interfaces']; } if (array_key_exists('templates_clear', $data)) { $updateTemplatesClear = zbx_toArray($data['templates_clear']); } if (isset($data['templates'])) { $updateTemplates = $data['templates']; } if (isset($data['macros'])) { $updateMacros = $data['macros']; } // second check is necessary, because import incorrectly inputs unset 'inventory' as empty string rather than null if (isset($data['inventory']) && $data['inventory']) { if (isset($data['inventory_mode']) && $data['inventory_mode'] == HOST_INVENTORY_DISABLED) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot set inventory fields for disabled inventory.')); } $updateInventory = $data['inventory']; $updateInventory['inventory_mode'] = null; } if (isset($data['inventory_mode'])) { if (!isset($updateInventory)) { $updateInventory = []; } $updateInventory['inventory_mode'] = $data['inventory_mode']; } if (isset($data['status'])) { $updateStatus = $data['status']; } unset($data['hosts'], $data['groups'], $data['interfaces'], $data['templates_clear'], $data['templates'], $data['macros'], $data['inventory'], $data['inventory_mode'], $data['status']); if (!zbx_empty($data)) { DB::update('hosts', ['values' => $data, 'where' => ['hostid' => $hostids]]); } if (isset($updateStatus)) { updateHostStatus($hostids, $updateStatus); } /* * Update template linkage */ if (isset($updateTemplatesClear)) { $templateIdsClear = zbx_objectValues($updateTemplatesClear, 'templateid'); if ($updateTemplatesClear) { $this->massRemove(['hostids' => $hostids, 'templateids_clear' => $templateIdsClear]); } } else { $templateIdsClear = []; } // unlink templates if (isset($updateTemplates)) { $hostTemplates = API::Template()->get(['hostids' => $hostids, 'output' => ['templateid'], 'preservekeys' => true]); $hostTemplateids = array_keys($hostTemplates); $newTemplateids = zbx_objectValues($updateTemplates, 'templateid'); $templatesToDel = array_diff($hostTemplateids, $newTemplateids); $templatesToDel = array_diff($templatesToDel, $templateIdsClear); if ($templatesToDel) { $result = $this->massRemove(['hostids' => $hostids, 'templateids' => $templatesToDel]); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot unlink template')); } } } /* * update interfaces */ if (isset($updateInterfaces)) { foreach ($hostids as $hostid) { API::HostInterface()->replaceHostInterfaces(['hostid' => $hostid, 'interfaces' => $updateInterfaces]); } } // link new templates if (isset($updateTemplates)) { $result = $this->massAdd(['hosts' => $hosts, 'templates' => $updateTemplates]); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot link template')); } } // macros if (isset($updateMacros)) { DB::delete('hostmacro', ['hostid' => $hostids]); $this->massAdd(['hosts' => $hosts, 'macros' => $updateMacros]); } /* * Inventory */ if (isset($updateInventory)) { // disabling inventory if ($updateInventory['inventory_mode'] == HOST_INVENTORY_DISABLED) { $sql = 'DELETE FROM host_inventory WHERE ' . dbConditionInt('hostid', $hostids); if (!DBexecute($sql)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete inventory.')); } } else { $existingInventoriesDb = DBfetchArrayAssoc(DBselect('SELECT hostid,inventory_mode' . ' FROM host_inventory' . ' WHERE ' . dbConditionInt('hostid', $hostids)), 'hostid'); // check existing host inventory data $automaticHostIds = []; if ($updateInventory['inventory_mode'] === null) { foreach ($hostids as $hostid) { // if inventory is disabled for one of the updated hosts, throw an exception if (!isset($existingInventoriesDb[$hostid])) { $host = get_host_by_hostid($hostid); self::exception(ZBX_API_ERROR_PARAMETERS, _s('Inventory disabled for host "%1$s".', $host['host'])); } elseif ($existingInventoriesDb[$hostid]['inventory_mode'] == HOST_INVENTORY_AUTOMATIC) { $automaticHostIds[] = $hostid; } } } $inventoriesToSave = []; foreach ($hostids as $hostid) { $hostInventory = $updateInventory; $hostInventory['hostid'] = $hostid; // if no 'inventory_mode' has been passed, set inventory 'inventory_mode' from DB if ($updateInventory['inventory_mode'] === null) { $hostInventory['inventory_mode'] = $existingInventoriesDb[$hostid]['inventory_mode']; } $inventoriesToSave[$hostid] = $hostInventory; } // when updating automatic inventory, ignore fields that have items linked to them if ($updateInventory['inventory_mode'] == HOST_INVENTORY_AUTOMATIC || $updateInventory['inventory_mode'] === null && $automaticHostIds) { $itemsToInventories = API::item()->get(['output' => ['inventory_link', 'hostid'], 'hostids' => $automaticHostIds ? $automaticHostIds : $hostids, 'nopermissions' => true]); $inventoryFields = getHostInventories(); foreach ($itemsToInventories as $hinv) { // 0 means 'no link' if ($hinv['inventory_link'] != 0) { $inventoryName = $inventoryFields[$hinv['inventory_link']]['db_field']; unset($inventoriesToSave[$hinv['hostid']][$inventoryName]); } } } // save inventory data foreach ($inventoriesToSave as $inventory) { $hostid = $inventory['hostid']; if (isset($existingInventoriesDb[$hostid])) { DB::update('host_inventory', ['values' => $inventory, 'where' => ['hostid' => $hostid]]); } else { DB::insert('host_inventory', [$inventory], false); } } } } /* * Update host and host group linkage. This procedure should be done the last because user can unlink * him self from a group with write permissions leaving only read premissions. Thus other procedures, like * host-template linkage, inventory update, macros update, must be done before this. */ if (isset($updateGroups)) { $updateGroups = zbx_toArray($updateGroups); $hostGroups = API::HostGroup()->get(['output' => ['groupid'], 'hostids' => $hostids]); $hostGroupIds = zbx_objectValues($hostGroups, 'groupid'); $newGroupIds = zbx_objectValues($updateGroups, 'groupid'); $groupsToAdd = array_diff($newGroupIds, $hostGroupIds); if ($groupsToAdd) { $this->massAdd(['hosts' => $hosts, 'groups' => zbx_toObject($groupsToAdd, 'groupid')]); } $groupIdsToDelete = array_diff($hostGroupIds, $newGroupIds); if ($groupIdsToDelete) { $this->massRemove(['hostids' => $hostids, 'groupids' => $groupIdsToDelete]); } } return ['hostids' => $inputHostIds]; }
/** * Unlinks the templates from the given hosts. If $tragetids is set to null, the templates will be unlinked from * all hosts. * * @param array $templateids * @param null|array $targetids the IDs of the hosts to unlink the templates from * @param bool $clear delete all of the inherited objects from the hosts */ protected function unlink($templateids, $targetids = null, $clear = false) { $flags = $clear ? array(ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE) : array(ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE, ZBX_FLAG_DISCOVERY_PROTOTYPE); // check that all triggers on templates that we unlink, don't have items from another templates $sql = 'SELECT DISTINCT t.description' . ' FROM triggers t,functions f,items i' . ' WHERE t.triggerid=f.triggerid' . ' AND f.itemid=i.itemid' . ' AND ' . dbConditionInt('i.hostid', $templateids) . ' AND EXISTS (' . 'SELECT ff.triggerid' . ' FROM functions ff,items ii' . ' WHERE ff.itemid=ii.itemid' . ' AND ff.triggerid=t.triggerid' . ' AND ' . dbConditionInt('ii.hostid', $templateids, true) . ')' . ' AND t.flags=' . ZBX_FLAG_DISCOVERY_NORMAL; if ($dbTrigger = DBfetch(DBSelect($sql, 1))) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot unlink trigger "%s", it has items from template that is left linked to host.', $dbTrigger['description'])); } $sqlFrom = ' triggers t,hosts h'; $sqlWhere = ' EXISTS (' . 'SELECT ff.triggerid' . ' FROM functions ff,items ii' . ' WHERE ff.triggerid=t.templateid' . ' AND ii.itemid=ff.itemid' . ' AND ' . dbConditionInt('ii.hostid', $templateids) . ')' . ' AND ' . dbConditionInt('t.flags', $flags); if (!is_null($targetids)) { $sqlFrom = ' triggers t,functions f,items i,hosts h'; $sqlWhere .= ' AND ' . dbConditionInt('i.hostid', $targetids) . ' AND f.itemid=i.itemid' . ' AND t.triggerid=f.triggerid' . ' AND h.hostid=i.hostid'; } $sql = 'SELECT DISTINCT t.triggerid,t.description,t.flags,t.expression,h.name as host' . ' FROM ' . $sqlFrom . ' WHERE ' . $sqlWhere; $dbTriggers = DBSelect($sql); $triggers = array(ZBX_FLAG_DISCOVERY_NORMAL => array(), ZBX_FLAG_DISCOVERY_PROTOTYPE => array()); $triggerids = array(); while ($trigger = DBfetch($dbTriggers)) { $triggers[$trigger['flags']][$trigger['triggerid']] = array('description' => $trigger['description'], 'expression' => explode_exp($trigger['expression']), 'triggerid' => $trigger['triggerid'], 'host' => $trigger['host']); if (!in_array($trigger['triggerid'], $triggerids)) { array_push($triggerids, $trigger['triggerid']); } } if (!empty($triggers[ZBX_FLAG_DISCOVERY_NORMAL])) { if ($clear) { $result = API::Trigger()->delete(array_keys($triggers[ZBX_FLAG_DISCOVERY_NORMAL]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear triggers')); } } else { DB::update('triggers', array('values' => array('templateid' => 0), 'where' => array('triggerid' => array_keys($triggers[ZBX_FLAG_DISCOVERY_NORMAL])))); foreach ($triggers[ZBX_FLAG_DISCOVERY_NORMAL] as $trigger) { info(_s('Unlinked: Trigger "%1$s" on "%2$s".', $trigger['description'], $trigger['host'])); } } } if (!empty($triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { if ($clear) { $result = API::TriggerPrototype()->delete(array_keys($triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear triggers')); } } else { DB::update('triggers', array('values' => array('templateid' => 0), 'where' => array('triggerid' => array_keys($triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])))); foreach ($triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE] as $trigger) { info(_s('Unlinked: Trigger prototype "%1$s" on "%2$s".', $trigger['description'], $trigger['host'])); } } } /* ITEMS, DISCOVERY RULES {{{ */ $sqlFrom = ' items i1,items i2,hosts h'; $sqlWhere = ' i2.itemid=i1.templateid' . ' AND ' . dbConditionInt('i2.hostid', $templateids) . ' AND ' . dbConditionInt('i1.flags', $flags) . ' AND h.hostid=i1.hostid'; if (!is_null($targetids)) { $sqlWhere .= ' AND ' . dbConditionInt('i1.hostid', $targetids); } $sql = 'SELECT DISTINCT i1.itemid,i1.flags,i1.name,i1.hostid,h.name as host' . ' FROM ' . $sqlFrom . ' WHERE ' . $sqlWhere; $dbItems = DBSelect($sql); $items = array(ZBX_FLAG_DISCOVERY_NORMAL => array(), ZBX_FLAG_DISCOVERY_RULE => array(), ZBX_FLAG_DISCOVERY_PROTOTYPE => array()); while ($item = DBfetch($dbItems)) { $items[$item['flags']][$item['itemid']] = array('name' => $item['name'], 'host' => $item['host']); } if (!empty($items[ZBX_FLAG_DISCOVERY_RULE])) { if ($clear) { $result = API::DiscoveryRule()->delete(array_keys($items[ZBX_FLAG_DISCOVERY_RULE]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear discovery rules')); } } else { DB::update('items', array('values' => array('templateid' => 0), 'where' => array('itemid' => array_keys($items[ZBX_FLAG_DISCOVERY_RULE])))); foreach ($items[ZBX_FLAG_DISCOVERY_RULE] as $discoveryRule) { info(_s('Unlinked: Discovery rule "%1$s" on "%2$s".', $discoveryRule['name'], $discoveryRule['host'])); } } } if (!empty($items[ZBX_FLAG_DISCOVERY_NORMAL])) { if ($clear) { $result = API::Item()->delete(array_keys($items[ZBX_FLAG_DISCOVERY_NORMAL]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear items')); } } else { DB::update('items', array('values' => array('templateid' => 0), 'where' => array('itemid' => array_keys($items[ZBX_FLAG_DISCOVERY_NORMAL])))); foreach ($items[ZBX_FLAG_DISCOVERY_NORMAL] as $item) { info(_s('Unlinked: Item "%1$s" on "%2$s".', $item['name'], $item['host'])); } } } if (!empty($items[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { if ($clear) { $result = API::Itemprototype()->delete(array_keys($items[ZBX_FLAG_DISCOVERY_PROTOTYPE]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear item prototypes')); } } else { DB::update('items', array('values' => array('templateid' => 0), 'where' => array('itemid' => array_keys($items[ZBX_FLAG_DISCOVERY_PROTOTYPE])))); foreach ($items[ZBX_FLAG_DISCOVERY_PROTOTYPE] as $item) { info(_s('Unlinked: Item prototype "%1$s" on "%2$s".', $item['name'], $item['host'])); } } } /* }}} ITEMS, DISCOVERY RULES */ // host prototypes // we need only to unlink host prototypes. in case of unlink and clear they will be deleted together with LLD rules. if (!$clear && isset($items[ZBX_FLAG_DISCOVERY_RULE])) { $discoveryRuleIds = array_keys($items[ZBX_FLAG_DISCOVERY_RULE]); $hostPrototypes = DBfetchArrayAssoc(DBSelect('SELECT DISTINCT h.hostid,h.host,h3.host AS parent_host' . ' FROM hosts h' . ' INNER JOIN host_discovery hd ON h.hostid=hd.hostid' . ' INNER JOIN hosts h2 ON h.templateid=h2.hostid' . ' INNER JOIN host_discovery hd2 ON h.hostid=hd.hostid' . ' INNER JOIN items i ON hd.parent_itemid=i.itemid' . ' INNER JOIN hosts h3 ON i.hostid=h3.hostid' . ' WHERE ' . dbConditionInt('hd.parent_itemid', $discoveryRuleIds)), 'hostid'); if ($hostPrototypes) { DB::update('hosts', array('values' => array('templateid' => 0), 'where' => array('hostid' => array_keys($hostPrototypes)))); DB::update('group_prototype', array('values' => array('templateid' => 0), 'where' => array('hostid' => array_keys($hostPrototypes)))); foreach ($hostPrototypes as $hostPrototype) { info(_s('Unlinked: Host prototype "%1$s" on "%2$s".', $hostPrototype['host'], $hostPrototype['parent_host'])); } } } /* GRAPHS {{{ */ $sqlFrom = ' graphs g,hosts h'; $sqlWhere = ' EXISTS (' . 'SELECT ggi.graphid' . ' FROM graphs_items ggi,items ii' . ' WHERE ggi.graphid=g.templateid' . ' AND ii.itemid=ggi.itemid' . ' AND ' . dbConditionInt('ii.hostid', $templateids) . ')' . ' AND ' . dbConditionInt('g.flags', $flags); if (!is_null($targetids)) { $sqlFrom = ' graphs g,graphs_items gi,items i,hosts h'; $sqlWhere .= ' AND ' . dbConditionInt('i.hostid', $targetids) . ' AND gi.itemid=i.itemid' . ' AND g.graphid=gi.graphid' . ' AND h.hostid=i.hostid'; } $sql = 'SELECT DISTINCT g.graphid,g.name,g.flags,h.name as host' . ' FROM ' . $sqlFrom . ' WHERE ' . $sqlWhere; $dbGraphs = DBSelect($sql); $graphs = array(ZBX_FLAG_DISCOVERY_NORMAL => array(), ZBX_FLAG_DISCOVERY_PROTOTYPE => array()); while ($graph = DBfetch($dbGraphs)) { $graphs[$graph['flags']][$graph['graphid']] = array('name' => $graph['name'], 'graphid' => $graph['graphid'], 'host' => $graph['host']); } if (!empty($graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])) { if ($clear) { $result = API::GraphPrototype()->delete(array_keys($graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear graph prototypes')); } } else { DB::update('graphs', array('values' => array('templateid' => 0), 'where' => array('graphid' => array_keys($graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])))); foreach ($graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE] as $graph) { info(_s('Unlinked: Graph prototype "%1$s" on "%2$s".', $graph['name'], $graph['host'])); } } } if (!empty($graphs[ZBX_FLAG_DISCOVERY_NORMAL])) { if ($clear) { $result = API::Graph()->delete(array_keys($graphs[ZBX_FLAG_DISCOVERY_NORMAL]), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear graphs.')); } } else { DB::update('graphs', array('values' => array('templateid' => 0), 'where' => array('graphid' => array_keys($graphs[ZBX_FLAG_DISCOVERY_NORMAL])))); foreach ($graphs[ZBX_FLAG_DISCOVERY_NORMAL] as $graph) { info(_s('Unlinked: Graph "%1$s" on "%2$s".', $graph['name'], $graph['host'])); } } } /* }}} GRAPHS */ // http tests $sqlWhere = ''; if (!is_null($targetids)) { $sqlWhere = ' AND ' . dbConditionInt('ht1.hostid', $targetids); } $sql = 'SELECT DISTINCT ht1.httptestid,ht1.name,h.name as host' . ' FROM httptest ht1' . ' INNER JOIN httptest ht2 ON ht2.httptestid=ht1.templateid' . ' INNER JOIN hosts h ON h.hostid=ht1.hostid' . ' WHERE ' . dbConditionInt('ht2.hostid', $templateids) . $sqlWhere; $dbHttpTests = DBSelect($sql); $httpTests = array(); while ($httpTest = DBfetch($dbHttpTests)) { $httpTests[$httpTest['httptestid']] = array('name' => $httpTest['name'], 'host' => $httpTest['host']); } if (!empty($httpTests)) { if ($clear) { $result = API::HttpTest()->delete(array_keys($httpTests), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear Web scenarios.')); } } else { DB::update('httptest', array('values' => array('templateid' => 0), 'where' => array('httptestid' => array_keys($httpTests)))); foreach ($httpTests as $httpTest) { info(_s('Unlinked: Web scenario "%1$s" on "%2$s".', $httpTest['name'], $httpTest['host'])); } } } /* APPLICATIONS {{{ */ $sql = 'SELECT at.application_templateid,at.applicationid,h.name,h.host,h.hostid' . ' FROM applications a1,application_template at,applications a2,hosts h' . ' WHERE a1.applicationid=at.applicationid' . ' AND at.templateid=a2.applicationid' . ' AND ' . dbConditionInt('a2.hostid', $templateids) . ' AND a1.hostid=h.hostid'; if ($targetids) { $sql .= ' AND ' . dbConditionInt('a1.hostid', $targetids); } $query = DBselect($sql); $applicationTemplates = array(); while ($applicationTemplate = DBfetch($query)) { $applicationTemplates[] = array('applicationid' => $applicationTemplate['applicationid'], 'application_templateid' => $applicationTemplate['application_templateid'], 'name' => $applicationTemplate['name'], 'hostid' => $applicationTemplate['hostid'], 'host' => $applicationTemplate['host']); } if ($applicationTemplates) { // unlink applications from templates DB::delete('application_template', array('application_templateid' => zbx_objectValues($applicationTemplates, 'application_templateid'))); if ($clear) { // delete inherited applications that are no longer linked to any templates $applications = DBfetchArray(DBselect('SELECT a.applicationid' . ' FROM applications a' . ' LEFT JOIN application_template at ON a.applicationid=at.applicationid ' . ' WHERE ' . dbConditionInt('a.applicationid', zbx_objectValues($applicationTemplates, 'applicationid')) . ' AND at.applicationid IS NULL')); $result = API::Application()->delete(zbx_objectValues($applications, 'applicationid'), true); if (!$result) { self::exception(ZBX_API_ERROR_INTERNAL, _('Cannot unlink and clear applications.')); } } else { foreach ($applicationTemplates as $application) { info(_s('Unlinked: Application "%1$s" on "%2$s".', $application['name'], $application['host'])); } } } /* }}} APPLICATIONS */ parent::unlink($templateids, $targetids); }
/** * Get parent maps for current map. * * @param int $mapId * * @return array */ function getParentMaps($mapId) { $parentMaps = DBfetchArrayAssoc(DBselect('SELECT s.sysmapid,s.name' . ' FROM sysmaps s' . ' JOIN sysmaps_elements se ON se.sysmapid=s.sysmapid' . ' WHERE se.elementtype=' . SYSMAP_ELEMENT_TYPE_MAP . ' AND se.elementid=' . zbx_dbstr($mapId)), 'sysmapid'); CArrayHelper::sort($parentMaps, array('name')); return $parentMaps; }
/** * Mass update hosts. * * @param array $hosts multidimensional array with Hosts data * @param array $hosts['hosts'] Array of Host objects to update * @param string $hosts['fields']['host'] Host name. * @param array $hosts['fields']['groupids'] HostGroup IDs add Host to. * @param int $hosts['fields']['port'] Port. OPTIONAL * @param int $hosts['fields']['status'] Host Status. OPTIONAL * @param int $hosts['fields']['useip'] Use IP. OPTIONAL * @param string $hosts['fields']['dns'] DNS. OPTIONAL * @param string $hosts['fields']['ip'] IP. OPTIONAL * @param int $hosts['fields']['bulk'] bulk. OPTIONAL * @param int $hosts['fields']['proxy_hostid'] Proxy Host ID. OPTIONAL * @param int $hosts['fields']['ipmi_authtype'] IPMI authentication type. OPTIONAL * @param int $hosts['fields']['ipmi_privilege'] IPMI privilege. OPTIONAL * @param string $hosts['fields']['ipmi_username'] IPMI username. OPTIONAL * @param string $hosts['fields']['ipmi_password'] IPMI password. OPTIONAL * * @return boolean */ public function massUpdate($data) { $hosts = zbx_toArray($data['hosts']); $inputHostIds = zbx_objectValues($hosts, 'hostid'); $hostIds = array_unique($inputHostIds); sort($hostIds); $dbHosts = $this->get(array('hostids' => $hostIds, 'editable' => true, 'output' => array('hostid'), 'preservekeys' => true)); foreach ($hosts as $host) { if (!isset($dbHosts[$host['hostid']])) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); } } // check if hosts have at least 1 group if (isset($data['groups']) && empty($data['groups'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No groups for hosts.')); } /* * Update hosts properties */ if (isset($data['name'])) { if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update visible host name.')); } } if (isset($data['host'])) { if (!preg_match('/^' . ZBX_PREG_HOST_FORMAT . '$/', $data['host'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect characters used for host name "%s".', $data['host'])); } if (count($hosts) > 1) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot mass update host name.')); } $curHost = reset($hosts); $sameHostnameHost = $this->get(array('output' => array('hostid'), 'filter' => array('host' => $data['host']), 'nopermissions' => true, 'limit' => 1)); $sameHostnameHost = reset($sameHostnameHost); if ($sameHostnameHost && bccomp($sameHostnameHost['hostid'], $curHost['hostid']) != 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Host "%1$s" already exists.', $data['host'])); } // can't add host with the same name as existing template $sameHostnameTemplate = API::Template()->get(array('output' => array('templateid'), 'filter' => array('host' => $data['host']), 'nopermissions' => true, 'limit' => 1)); if ($sameHostnameTemplate) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Template "%1$s" already exists.', $data['host'])); } } if (isset($data['groups'])) { $updateGroups = $data['groups']; } if (isset($data['interfaces'])) { $updateInterfaces = $data['interfaces']; } $b = isset($data['templates_clear']); $c = array_key_exists('templates_clear', $data); $d = array_keys($data); if ($b) { $updateTemplatesClear = zbx_toArray($data['templates_clear']); } if (isset($data['templates'])) { $updateTemplates = $data['templates']; } if (isset($data['macros'])) { $updateMacros = $data['macros']; } // second check is necessary, because import incorrectly inputs unset 'inventory' as empty string rather than null if (isset($data['inventory']) && $data['inventory']) { if (isset($data['inventory_mode']) && $data['inventory_mode'] == HOST_INVENTORY_DISABLED) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot set inventory fields for disabled inventory.')); } $updateInventory = $data['inventory']; $updateInventory['inventory_mode'] = null; } if (isset($data['inventory_mode'])) { if (!isset($updateInventory)) { $updateInventory = array(); } $updateInventory['inventory_mode'] = $data['inventory_mode']; } if (isset($data['status'])) { $updateStatus = $data['status']; } unset($data['hosts'], $data['groups'], $data['interfaces'], $data['templates_clear'], $data['templates'], $data['macros'], $data['inventory'], $data['inventory_mode'], $data['status']); if (!zbx_empty($data)) { DB::update('hosts', array('values' => $data, 'where' => array('hostid' => $hostIds))); } if (isset($updateStatus)) { updateHostStatus($hostIds, $updateStatus); } /* * Update hostgroups linkage */ if (isset($updateGroups)) { $updateGroups = zbx_toArray($updateGroups); $hostGroups = API::HostGroup()->get(array('output' => array('groupid'), 'hostids' => $hostIds)); $hostGroupIds = zbx_objectValues($hostGroups, 'groupid'); $newGroupIds = zbx_objectValues($updateGroups, 'groupid'); $result = $this->massAdd(array('hosts' => $hosts, 'groups' => $updateGroups)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot create host group.')); } $groupIdsToDel = array_diff($hostGroupIds, $newGroupIds); if ($groupIdsToDel) { $result = $this->massRemove(array('hostids' => $hostIds, 'groupids' => $groupIdsToDel)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete host group.')); } } } /* * Update template linkage */ if (isset($updateTemplatesClear)) { $templateIdsClear = zbx_objectValues($updateTemplatesClear, 'templateid'); if ($updateTemplatesClear) { $this->massRemove(array('hostids' => $hostIds, 'templateids_clear' => $templateIdsClear)); } } else { $templateIdsClear = array(); } // unlink templates if (isset($updateTemplates)) { $hostTemplates = API::Template()->get(array('hostids' => $hostIds, 'output' => array('templateid'), 'preservekeys' => true)); $hostTemplateids = array_keys($hostTemplates); $newTemplateids = zbx_objectValues($updateTemplates, 'templateid'); $templatesToDel = array_diff($hostTemplateids, $newTemplateids); $templatesToDel = array_diff($templatesToDel, $templateIdsClear); if ($templatesToDel) { $result = $this->massRemove(array('hostids' => $hostIds, 'templateids' => $templatesToDel)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot unlink template')); } } } /* * update interfaces */ if (isset($updateInterfaces)) { foreach ($hostIds as $hostId) { API::HostInterface()->replaceHostInterfaces(array('hostid' => $hostId, 'interfaces' => $updateInterfaces)); } } // link new templates if (isset($updateTemplates)) { $result = $this->massAdd(array('hosts' => $hosts, 'templates' => $updateTemplates)); if (!$result) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot link template')); } } // macros if (isset($updateMacros)) { DB::delete('hostmacro', array('hostid' => $hostIds)); $this->massAdd(array('hosts' => $hosts, 'macros' => $updateMacros)); } /* * Inventory */ if (isset($updateInventory)) { // disabling inventory if ($updateInventory['inventory_mode'] == HOST_INVENTORY_DISABLED) { $sql = 'DELETE FROM host_inventory WHERE ' . dbConditionInt('hostid', $hostIds); if (!DBexecute($sql)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete inventory.')); } } else { $existingInventoriesDb = DBfetchArrayAssoc(DBselect('SELECT hostid,inventory_mode' . ' FROM host_inventory' . ' WHERE ' . dbConditionInt('hostid', $hostIds)), 'hostid'); // check existing host inventory data $automaticHostIds = array(); if ($updateInventory['inventory_mode'] === null) { foreach ($hostIds as $hostId) { // if inventory is disabled for one of the updated hosts, throw an exception if (!isset($existingInventoriesDb[$hostId])) { $host = get_host_by_hostid($hostId); self::exception(ZBX_API_ERROR_PARAMETERS, _s('Inventory disabled for host "%1$s".', $host['host'])); } elseif ($existingInventoriesDb[$hostId]['inventory_mode'] == HOST_INVENTORY_AUTOMATIC) { $automaticHostIds[] = $hostId; } } } $inventoriesToSave = array(); foreach ($hostIds as $hostId) { $hostInventory = $updateInventory; $hostInventory['hostid'] = $hostId; // if no 'inventory_mode' has been passed, set inventory 'inventory_mode' from DB if ($updateInventory['inventory_mode'] === null) { $hostInventory['inventory_mode'] = $existingInventoriesDb[$hostId]['inventory_mode']; } $inventoriesToSave[$hostId] = $hostInventory; } // when updating automatic inventory, ignore fields that have items linked to them if ($updateInventory['inventory_mode'] == HOST_INVENTORY_AUTOMATIC || $updateInventory['inventory_mode'] === null && $automaticHostIds) { $itemsToInventories = API::item()->get(array('output' => array('inventory_link', 'hostid'), 'hostids' => $automaticHostIds ? $automaticHostIds : $hostIds, 'nopermissions' => true)); $inventoryFields = getHostInventories(); foreach ($itemsToInventories as $hinv) { // 0 means 'no link' if ($hinv['inventory_link'] != 0) { $inventoryName = $inventoryFields[$hinv['inventory_link']]['db_field']; unset($inventoriesToSave[$hinv['hostid']][$inventoryName]); } } } // save inventory data foreach ($inventoriesToSave as $inventory) { $hostId = $inventory['hostid']; if (isset($existingInventoriesDb[$hostId])) { DB::update('host_inventory', array('values' => $inventory, 'where' => array('hostid' => $hostId))); } else { DB::insert('host_inventory', array($inventory), false); } } } } return array('hostids' => $inputHostIds); }