/** * 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]; }
/** * Get data for item edit page. * * @param array $item item, item prototype or LLD rule to take the data from * @param bool $options['is_discovery_rule'] * * @return array */ function getItemFormData(array $item = array(), array $options = array()) { $data = array('form' => getRequest('form'), 'form_refresh' => getRequest('form_refresh'), 'is_discovery_rule' => !empty($options['is_discovery_rule']), 'parent_discoveryid' => getRequest('parent_discoveryid', !empty($options['is_discovery_rule']) ? getRequest('itemid') : null), 'itemid' => getRequest('itemid'), 'limited' => false, 'interfaceid' => getRequest('interfaceid', 0), 'name' => getRequest('name', ''), 'description' => getRequest('description', ''), 'key' => getRequest('key', ''), 'hostname' => getRequest('hostname'), 'delay' => getRequest('delay', ZBX_ITEM_DELAY_DEFAULT), 'history' => getRequest('history', 90), 'status' => getRequest('status', isset($_REQUEST['form_refresh']) ? 1 : 0), 'type' => getRequest('type', 0), 'snmp_community' => getRequest('snmp_community', 'public'), 'snmp_oid' => getRequest('snmp_oid', 'interfaces.ifTable.ifEntry.ifInOctets.1'), 'port' => getRequest('port', ''), 'value_type' => getRequest('value_type', ITEM_VALUE_TYPE_UINT64), 'data_type' => getRequest('data_type', ITEM_DATA_TYPE_DECIMAL), 'trapper_hosts' => getRequest('trapper_hosts', ''), 'units' => getRequest('units', ''), 'valuemapid' => getRequest('valuemapid', 0), 'params' => getRequest('params', ''), 'multiplier' => getRequest('multiplier', 0), 'delta' => getRequest('delta', 0), 'trends' => getRequest('trends', DAY_IN_YEAR), 'new_application' => getRequest('new_application', ''), 'applications' => getRequest('applications', array()), 'delay_flex' => getRequest('delay_flex', array()), 'new_delay_flex' => getRequest('new_delay_flex', array('delay' => 50, 'period' => ZBX_DEFAULT_INTERVAL)), 'snmpv3_contextname' => getRequest('snmpv3_contextname', ''), 'snmpv3_securityname' => getRequest('snmpv3_securityname', ''), 'snmpv3_securitylevel' => getRequest('snmpv3_securitylevel', 0), 'snmpv3_authprotocol' => getRequest('snmpv3_authprotocol', ITEM_AUTHPROTOCOL_MD5), 'snmpv3_authpassphrase' => getRequest('snmpv3_authpassphrase', ''), 'snmpv3_privprotocol' => getRequest('snmpv3_privprotocol', ITEM_PRIVPROTOCOL_DES), 'snmpv3_privpassphrase' => getRequest('snmpv3_privpassphrase', ''), 'ipmi_sensor' => getRequest('ipmi_sensor', ''), 'authtype' => getRequest('authtype', 0), 'username' => getRequest('username', ''), 'password' => getRequest('password', ''), 'publickey' => getRequest('publickey', ''), 'privatekey' => getRequest('privatekey', ''), 'formula' => getRequest('formula', 1), 'logtimefmt' => getRequest('logtimefmt', ''), 'add_groupid' => getRequest('add_groupid', getRequest('groupid', 0)), 'valuemaps' => null, 'possibleHostInventories' => null, 'alreadyPopulated' => null, 'initial_item_type' => null, 'templates' => array()); // hostid if (!empty($data['parent_discoveryid'])) { $discoveryRule = API::DiscoveryRule()->get(array('itemids' => $data['parent_discoveryid'], 'output' => API_OUTPUT_EXTEND, 'editable' => true)); $discoveryRule = reset($discoveryRule); $data['hostid'] = $discoveryRule['hostid']; } else { $data['hostid'] = getRequest('hostid', 0); } // types, http items only for internal processes $data['types'] = item_type2str(); unset($data['types'][ITEM_TYPE_HTTPTEST]); if (!empty($options['is_discovery_rule'])) { unset($data['types'][ITEM_TYPE_AGGREGATE], $data['types'][ITEM_TYPE_CALCULATED], $data['types'][ITEM_TYPE_SNMPTRAP]); } // item if ($item) { $data['item'] = $item; $data['hostid'] = !empty($data['hostid']) ? $data['hostid'] : $data['item']['hostid']; $data['limited'] = $data['item']['templateid'] != 0; // get templates $itemid = $item['itemid']; do { $params = array('itemids' => $itemid, 'output' => array('itemid', 'templateid'), 'selectHosts' => array('name')); if ($data['is_discovery_rule']) { $item = API::DiscoveryRule()->get($params); } else { $params['selectDiscoveryRule'] = array('itemid'); $params['filter'] = array('flags' => null); $item = API::Item()->get($params); } $item = reset($item); if (!empty($item)) { $host = reset($item['hosts']); if (!empty($item['hosts'])) { $host['name'] = CHtml::encode($host['name']); if (bccomp($data['itemid'], $itemid) == 0) { } elseif ($data['is_discovery_rule']) { $data['templates'][] = new CLink($host['name'], 'host_discovery.php?form=update&itemid=' . $item['itemid'], 'highlight underline weight_normal'); $data['templates'][] = SPACE . '⇒' . SPACE; } elseif ($item['discoveryRule']) { $data['templates'][] = new CLink($host['name'], 'disc_prototypes.php?form=update&itemid=' . $item['itemid'] . '&parent_discoveryid=' . $item['discoveryRule']['itemid'], 'highlight underline weight_normal'); $data['templates'][] = SPACE . '⇒' . SPACE; } else { $data['templates'][] = new CLink($host['name'], 'items.php?form=update&itemid=' . $item['itemid'], 'highlight underline weight_normal'); $data['templates'][] = SPACE . '⇒' . SPACE; } } $itemid = $item['templateid']; } else { break; } } while ($itemid != 0); $data['templates'] = array_reverse($data['templates']); array_shift($data['templates']); } // caption if (!empty($data['is_discovery_rule'])) { $data['caption'] = _('Discovery rule'); } else { $data['caption'] = !empty($data['parent_discoveryid']) ? _('Item prototype') : _('Item'); } // hostname if (empty($data['is_discovery_rule']) && empty($data['hostname'])) { if (!empty($data['hostid'])) { $hostInfo = API::Host()->get(array('hostids' => $data['hostid'], 'output' => array('name'), 'templated_hosts' => true)); $hostInfo = reset($hostInfo); $data['hostname'] = $hostInfo['name']; } else { $data['hostname'] = _('not selected'); } } // fill data from item if (!hasRequest('form_refresh') && ($item || $data['limited'])) { $data['name'] = $data['item']['name']; $data['description'] = $data['item']['description']; $data['key'] = $data['item']['key_']; $data['interfaceid'] = $data['item']['interfaceid']; $data['type'] = $data['item']['type']; $data['snmp_community'] = $data['item']['snmp_community']; $data['snmp_oid'] = $data['item']['snmp_oid']; $data['port'] = $data['item']['port']; $data['value_type'] = $data['item']['value_type']; $data['data_type'] = $data['item']['data_type']; $data['trapper_hosts'] = $data['item']['trapper_hosts']; $data['units'] = $data['item']['units']; $data['valuemapid'] = $data['item']['valuemapid']; $data['multiplier'] = $data['item']['multiplier']; $data['hostid'] = $data['item']['hostid']; $data['params'] = $data['item']['params']; $data['snmpv3_contextname'] = $data['item']['snmpv3_contextname']; $data['snmpv3_securityname'] = $data['item']['snmpv3_securityname']; $data['snmpv3_securitylevel'] = $data['item']['snmpv3_securitylevel']; $data['snmpv3_authprotocol'] = $data['item']['snmpv3_authprotocol']; $data['snmpv3_authpassphrase'] = $data['item']['snmpv3_authpassphrase']; $data['snmpv3_privprotocol'] = $data['item']['snmpv3_privprotocol']; $data['snmpv3_privpassphrase'] = $data['item']['snmpv3_privpassphrase']; $data['ipmi_sensor'] = $data['item']['ipmi_sensor']; $data['authtype'] = $data['item']['authtype']; $data['username'] = $data['item']['username']; $data['password'] = $data['item']['password']; $data['publickey'] = $data['item']['publickey']; $data['privatekey'] = $data['item']['privatekey']; $data['logtimefmt'] = $data['item']['logtimefmt']; $data['new_application'] = getRequest('new_application', ''); if (!$data['is_discovery_rule']) { $data['formula'] = $data['item']['formula']; } if (!$data['limited'] || !isset($_REQUEST['form_refresh'])) { $data['delay'] = $data['item']['delay']; if (($data['type'] == ITEM_TYPE_TRAPPER || $data['type'] == ITEM_TYPE_SNMPTRAP) && $data['delay'] == 0) { $data['delay'] = ZBX_ITEM_DELAY_DEFAULT; } $data['history'] = $data['item']['history']; $data['status'] = $data['item']['status']; $data['delta'] = $data['item']['delta']; $data['trends'] = $data['item']['trends']; $db_delay_flex = $data['item']['delay_flex']; if (isset($db_delay_flex)) { $arr_of_dellays = explode(';', $db_delay_flex); foreach ($arr_of_dellays as $one_db_delay) { $arr_of_delay = explode('/', $one_db_delay); if (!isset($arr_of_delay[0]) || !isset($arr_of_delay[1])) { continue; } array_push($data['delay_flex'], array('delay' => $arr_of_delay[0], 'period' => $arr_of_delay[1])); } } $data['applications'] = array_unique(zbx_array_merge($data['applications'], get_applications_by_itemid($data['itemid']))); } } // applications if (count($data['applications']) == 0) { array_push($data['applications'], 0); } $data['db_applications'] = DBfetchArray(DBselect('SELECT DISTINCT a.applicationid,a.name' . ' FROM applications a' . ' WHERE a.hostid=' . zbx_dbstr($data['hostid']))); order_result($data['db_applications'], 'name'); // interfaces $data['interfaces'] = API::HostInterface()->get(array('hostids' => $data['hostid'], 'output' => API_OUTPUT_EXTEND)); // valuemapid if ($data['limited']) { if (!empty($data['valuemapid'])) { if ($map_data = DBfetch(DBselect('SELECT v.name FROM valuemaps v WHERE v.valuemapid=' . zbx_dbstr($data['valuemapid'])))) { $data['valuemaps'] = $map_data['name']; } } } else { $data['valuemaps'] = DBfetchArray(DBselect('SELECT v.* FROM valuemaps v')); order_result($data['valuemaps'], 'name'); } // possible host inventories if (empty($data['parent_discoveryid'])) { $data['possibleHostInventories'] = getHostInventories(); // get already populated fields by other items $data['alreadyPopulated'] = API::item()->get(array('output' => array('inventory_link'), 'filter' => array('hostid' => $data['hostid']), 'nopermissions' => true)); $data['alreadyPopulated'] = zbx_toHash($data['alreadyPopulated'], 'inventory_link'); } // template $data['is_template'] = isTemplate($data['hostid']); // unset snmpv3 fields if ($data['type'] != ITEM_TYPE_SNMPV3) { $data['snmpv3_contextname'] = ''; $data['snmpv3_securityname'] = ''; $data['snmpv3_securitylevel'] = ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV; $data['snmpv3_authprotocol'] = ITEM_AUTHPROTOCOL_MD5; $data['snmpv3_authpassphrase'] = ''; $data['snmpv3_privprotocol'] = ITEM_PRIVPROTOCOL_DES; $data['snmpv3_privpassphrase'] = ''; } // unset ssh auth fields if ($data['type'] != ITEM_TYPE_SSH) { $data['authtype'] = ITEM_AUTHTYPE_PASSWORD; $data['publickey'] = ''; $data['privatekey'] = ''; } return $data; }
/** * * @return object|null */ public function getItem($id) { return API::item($id); }
/** * 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']); $hostids = zbx_objectValues($hosts, 'hostid'); $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' => API_OUTPUT_SHORTEN, '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']; unset($data['groups']); } if (isset($data['interfaces'])) { $updateInterfaces = $data['interfaces']; unset($data['interfaces']); } if (isset($data['templates_clear'])) { $updateTemplatesClear = zbx_toArray($data['templates_clear']); unset($data['templates_clear']); } if (isset($data['templates'])) { $updateTemplates = $data['templates']; unset($data['templates']); } if (isset($data['macros'])) { $updateMacros = $data['macros']; unset($data['macros']); } if (isset($data['inventory'])) { $updateInventory = $data['inventory']; unset($data['inventory']); } if (isset($data['inventory_mode'])) { if (!isset($updateInventory)) { $updateInventory = array(); } $updateInventory['inventory_mode'] = $data['inventory_mode']; unset($data['inventory_mode']); } if (isset($data['status'])) { $updateStatus = $data['status']; unset($data['status']); } unset($data['hosts']); if (!zbx_empty($data)) { $update = array('values' => $data, 'where' => array('hostid' => $hostids)); DB::update('hosts', $update); } 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 (!empty($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 (!empty($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' => API_OUTPUT_SHORTEN, 'preservekeys' => true)); $hostTemplateids = array_keys($hostTemplates); $newTemplateids = zbx_objectValues($updateTemplates, 'templateid'); $templatesToDel = array_diff($hostTemplateids, $newTemplateids); $templatesToDel = array_diff($templatesToDel, $templateidsClear); if (!empty($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 = DBselect('SELECT hostid FROM host_inventory WHERE ' . dbConditionInt('hostid', $hostids)); while ($existingInventory = DBfetch($existingInventoriesDb)) { $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' => $hostids); }
/** * Get data for item edit page. * * @param array $item item, item prototype or LLD rule to take the data from * @param bool $options['is_discovery_rule'] * * @return array */ function getItemFormData(array $item = [], array $options = []) { $data = ['form' => getRequest('form'), 'form_refresh' => getRequest('form_refresh'), 'is_discovery_rule' => !empty($options['is_discovery_rule']), 'parent_discoveryid' => getRequest('parent_discoveryid', !empty($options['is_discovery_rule']) ? getRequest('itemid') : null), 'itemid' => getRequest('itemid'), 'limited' => false, 'interfaceid' => getRequest('interfaceid', 0), 'name' => getRequest('name', ''), 'description' => getRequest('description', ''), 'key' => getRequest('key', ''), 'hostname' => getRequest('hostname'), 'delay' => getRequest('delay', ZBX_ITEM_DELAY_DEFAULT), 'history' => getRequest('history', 90), 'status' => getRequest('status', isset($_REQUEST['form_refresh']) ? 1 : 0), 'type' => getRequest('type', 0), 'snmp_community' => getRequest('snmp_community', 'public'), 'snmp_oid' => getRequest('snmp_oid', 'interfaces.ifTable.ifEntry.ifInOctets.1'), 'port' => getRequest('port', ''), 'value_type' => getRequest('value_type', ITEM_VALUE_TYPE_UINT64), 'data_type' => getRequest('data_type', ITEM_DATA_TYPE_DECIMAL), 'trapper_hosts' => getRequest('trapper_hosts', ''), 'units' => getRequest('units', ''), 'valuemapid' => getRequest('valuemapid', 0), 'params' => getRequest('params', ''), 'multiplier' => getRequest('multiplier', 0), 'delta' => getRequest('delta', 0), 'trends' => getRequest('trends', DAY_IN_YEAR), 'new_application' => getRequest('new_application', ''), 'applications' => getRequest('applications', []), 'delay_flex' => getRequest('delay_flex', []), 'snmpv3_contextname' => getRequest('snmpv3_contextname', ''), 'snmpv3_securityname' => getRequest('snmpv3_securityname', ''), 'snmpv3_securitylevel' => getRequest('snmpv3_securitylevel', 0), 'snmpv3_authprotocol' => getRequest('snmpv3_authprotocol', ITEM_AUTHPROTOCOL_MD5), 'snmpv3_authpassphrase' => getRequest('snmpv3_authpassphrase', ''), 'snmpv3_privprotocol' => getRequest('snmpv3_privprotocol', ITEM_PRIVPROTOCOL_DES), 'snmpv3_privpassphrase' => getRequest('snmpv3_privpassphrase', ''), 'ipmi_sensor' => getRequest('ipmi_sensor', ''), 'authtype' => getRequest('authtype', 0), 'username' => getRequest('username', ''), 'password' => getRequest('password', ''), 'publickey' => getRequest('publickey', ''), 'privatekey' => getRequest('privatekey', ''), 'formula' => getRequest('formula', 1), 'logtimefmt' => getRequest('logtimefmt', ''), 'add_groupid' => getRequest('add_groupid', getRequest('groupid', 0)), 'valuemaps' => null, 'possibleHostInventories' => null, 'alreadyPopulated' => null, 'initial_item_type' => null, 'templates' => []]; // hostid if (!empty($data['parent_discoveryid'])) { $discoveryRule = API::DiscoveryRule()->get(['itemids' => $data['parent_discoveryid'], 'output' => API_OUTPUT_EXTEND, 'editable' => true]); $discoveryRule = reset($discoveryRule); $data['hostid'] = $discoveryRule['hostid']; $data['new_application_prototype'] = getRequest('new_application_prototype', ''); $data['application_prototypes'] = getRequest('application_prototypes', array()); } else { $data['hostid'] = getRequest('hostid', 0); } // types, http items only for internal processes $data['types'] = item_type2str(); unset($data['types'][ITEM_TYPE_HTTPTEST]); if (!empty($options['is_discovery_rule'])) { unset($data['types'][ITEM_TYPE_AGGREGATE], $data['types'][ITEM_TYPE_CALCULATED], $data['types'][ITEM_TYPE_SNMPTRAP]); } // item if ($item) { $data['item'] = $item; $data['hostid'] = !empty($data['hostid']) ? $data['hostid'] : $data['item']['hostid']; $data['limited'] = $data['item']['templateid'] != 0; // get templates $itemid = $item['itemid']; do { $params = ['itemids' => $itemid, 'output' => ['itemid', 'templateid'], 'selectHosts' => ['name']]; if ($data['is_discovery_rule']) { $item = API::DiscoveryRule()->get($params); } else { $params['selectDiscoveryRule'] = ['itemid']; $params['filter'] = ['flags' => null]; $item = API::Item()->get($params); } $item = reset($item); if (!empty($item)) { $host = reset($item['hosts']); if (!empty($item['hosts'])) { $host['name'] = CHtml::encode($host['name']); if (bccomp($data['itemid'], $itemid) == 0) { } elseif ($data['is_discovery_rule']) { $data['templates'][] = new CLink($host['name'], 'host_discovery.php?form=update&itemid=' . $item['itemid']); $data['templates'][] = SPACE . '⇒' . SPACE; } elseif ($item['discoveryRule']) { $data['templates'][] = new CLink($host['name'], 'disc_prototypes.php?form=update' . '&itemid=' . $item['itemid'] . '&parent_discoveryid=' . $item['discoveryRule']['itemid']); $data['templates'][] = SPACE . '⇒' . SPACE; } else { $data['templates'][] = new CLink($host['name'], 'items.php?form=update&itemid=' . $item['itemid']); $data['templates'][] = SPACE . '⇒' . SPACE; } } $itemid = $item['templateid']; } else { break; } } while ($itemid != 0); $data['templates'] = array_reverse($data['templates']); array_shift($data['templates']); } // caption if (!empty($data['is_discovery_rule'])) { $data['caption'] = _('Discovery rule'); } else { $data['caption'] = !empty($data['parent_discoveryid']) ? _('Item prototype') : _('Item'); } // hostname if (empty($data['is_discovery_rule']) && empty($data['hostname'])) { if (!empty($data['hostid'])) { $hostInfo = API::Host()->get(['hostids' => $data['hostid'], 'output' => ['name'], 'templated_hosts' => true]); $hostInfo = reset($hostInfo); $data['hostname'] = $hostInfo['name']; } else { $data['hostname'] = _('not selected'); } } // fill data from item if (!hasRequest('form_refresh') && ($item || $data['limited'])) { $data['name'] = $data['item']['name']; $data['description'] = $data['item']['description']; $data['key'] = $data['item']['key_']; $data['interfaceid'] = $data['item']['interfaceid']; $data['type'] = $data['item']['type']; $data['snmp_community'] = $data['item']['snmp_community']; $data['snmp_oid'] = $data['item']['snmp_oid']; $data['port'] = $data['item']['port']; $data['value_type'] = $data['item']['value_type']; $data['data_type'] = $data['item']['data_type']; $data['trapper_hosts'] = $data['item']['trapper_hosts']; $data['units'] = $data['item']['units']; $data['valuemapid'] = $data['item']['valuemapid']; $data['multiplier'] = $data['item']['multiplier']; $data['hostid'] = $data['item']['hostid']; $data['params'] = $data['item']['params']; $data['snmpv3_contextname'] = $data['item']['snmpv3_contextname']; $data['snmpv3_securityname'] = $data['item']['snmpv3_securityname']; $data['snmpv3_securitylevel'] = $data['item']['snmpv3_securitylevel']; $data['snmpv3_authprotocol'] = $data['item']['snmpv3_authprotocol']; $data['snmpv3_authpassphrase'] = $data['item']['snmpv3_authpassphrase']; $data['snmpv3_privprotocol'] = $data['item']['snmpv3_privprotocol']; $data['snmpv3_privpassphrase'] = $data['item']['snmpv3_privpassphrase']; $data['ipmi_sensor'] = $data['item']['ipmi_sensor']; $data['authtype'] = $data['item']['authtype']; $data['username'] = $data['item']['username']; $data['password'] = $data['item']['password']; $data['publickey'] = $data['item']['publickey']; $data['privatekey'] = $data['item']['privatekey']; $data['logtimefmt'] = $data['item']['logtimefmt']; $data['new_application'] = getRequest('new_application', ''); if ($data['parent_discoveryid'] != 0) { $data['new_application_prototype'] = getRequest('new_application_prototype', ''); } if (!$data['is_discovery_rule']) { $data['formula'] = $data['item']['formula']; } if (!$data['limited'] || !isset($_REQUEST['form_refresh'])) { $data['delay'] = $data['item']['delay']; if (($data['type'] == ITEM_TYPE_TRAPPER || $data['type'] == ITEM_TYPE_SNMPTRAP) && $data['delay'] == 0) { $data['delay'] = ZBX_ITEM_DELAY_DEFAULT; } $data['history'] = $data['item']['history']; $data['status'] = $data['item']['status']; $data['delta'] = $data['item']['delta']; $data['trends'] = $data['item']['trends']; $parser = new CItemDelayFlexParser($data['item']['delay_flex']); if ($parser->isValid()) { foreach ($parser->getIntervals() as $interval) { if ($interval['type'] == ITEM_DELAY_FLEX_TYPE_FLEXIBLE) { $interval_parts = explode('/', $interval['interval']); $data['delay_flex'][] = ['delay' => $interval_parts[0], 'period' => $interval_parts[1], 'type' => ITEM_DELAY_FLEX_TYPE_FLEXIBLE]; } else { $data['delay_flex'][] = ['schedule' => $interval['interval'], 'type' => ITEM_DELAY_FLEX_TYPE_SCHEDULING]; } } } $data['applications'] = array_unique(zbx_array_merge($data['applications'], get_applications_by_itemid($data['itemid']))); if ($data['parent_discoveryid'] != 0) { /* * Get a list of application prototypes assigned to item prototype. Don't select distinct names, * since database can be accidentally created case insensitive. */ $application_prototypes = DBfetchArray(DBselect('SELECT ap.name' . ' FROM application_prototype ap,item_application_prototype iap' . ' WHERE ap.application_prototypeid=iap.application_prototypeid' . ' AND ap.itemid=' . zbx_dbstr($data['parent_discoveryid']) . ' AND iap.itemid=' . zbx_dbstr($data['itemid']))); // Merge form submitted data with data existing in DB to find diff and correctly display ListBox. $data['application_prototypes'] = array_unique(zbx_array_merge($data['application_prototypes'], zbx_objectValues($application_prototypes, 'name'))); } } } if (!$data['delay_flex']) { $data['delay_flex'][] = ['delay' => '', 'period' => '', 'type' => ITEM_DELAY_FLEX_TYPE_FLEXIBLE]; } // applications if (count($data['applications']) == 0) { array_push($data['applications'], 0); } $data['db_applications'] = DBfetchArray(DBselect('SELECT DISTINCT a.applicationid,a.name' . ' FROM applications a' . ' WHERE a.hostid=' . zbx_dbstr($data['hostid']) . ($data['parent_discoveryid'] ? ' AND a.flags=' . ZBX_FLAG_DISCOVERY_NORMAL : ''))); order_result($data['db_applications'], 'name'); if ($data['parent_discoveryid'] != 0) { // Make the application prototype list no appearing empty, but filling it with "-None-" as first element. if (count($data['application_prototypes']) == 0) { $data['application_prototypes'][] = 0; } // Get a list of application prototypes by discovery rule. $data['db_application_prototypes'] = DBfetchArray(DBselect('SELECT ap.application_prototypeid,ap.name' . ' FROM application_prototype ap' . ' WHERE ap.itemid=' . zbx_dbstr($data['parent_discoveryid']))); order_result($data['db_application_prototypes'], 'name'); } // interfaces $data['interfaces'] = API::HostInterface()->get(['hostids' => $data['hostid'], 'output' => API_OUTPUT_EXTEND]); // valuemapid if ($data['limited']) { if ($data['valuemapid'] != 0) { $valuemaps = API::ValueMap()->get(['output' => ['name'], 'valuemapids' => [$data['valuemapid']]]); if ($valuemaps) { $data['valuemaps'] = $valuemaps[0]['name']; } } } else { $data['valuemaps'] = API::ValueMap()->get(['output' => ['valemapid', 'name']]); CArrayHelper::sort($data['valuemaps'], ['name']); } // possible host inventories if (empty($data['parent_discoveryid'])) { $data['possibleHostInventories'] = getHostInventories(); // get already populated fields by other items $data['alreadyPopulated'] = API::item()->get(['output' => ['inventory_link'], 'filter' => ['hostid' => $data['hostid']], 'nopermissions' => true]); $data['alreadyPopulated'] = zbx_toHash($data['alreadyPopulated'], 'inventory_link'); } // unset snmpv3 fields if ($data['type'] != ITEM_TYPE_SNMPV3) { $data['snmpv3_contextname'] = ''; $data['snmpv3_securityname'] = ''; $data['snmpv3_securitylevel'] = ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV; $data['snmpv3_authprotocol'] = ITEM_AUTHPROTOCOL_MD5; $data['snmpv3_authpassphrase'] = ''; $data['snmpv3_privprotocol'] = ITEM_PRIVPROTOCOL_DES; $data['snmpv3_privpassphrase'] = ''; } // unset ssh auth fields if ($data['type'] != ITEM_TYPE_SSH) { $data['authtype'] = ITEM_AUTHTYPE_PASSWORD; $data['publickey'] = ''; $data['privatekey'] = ''; } return $data; }
/** * 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); }