/** * Validate write permissions to host groups that are removed from given hosts and templates. Also check * if host and template has at least one host group left. * * @param array $data * @param array $data['groupids'] * @param array $data['hostids'] * @param array $data['templateids'] * * @throws APIException if user has no write permissions to any of the given host groups or one of the hosts and * templates is left without a host group */ protected function validateMassRemove(array $data) { $groupIdsToRemove = array(); $hostIds = isset($data['hostids']) ? $data['hostids'] : array(); $templateIds = isset($data['templateids']) ? $data['templateids'] : array(); $objectIds = array(); if ($hostIds) { $dbHosts = API::Host()->get(array('output' => array('hostid'), 'selectGroups' => array('groupid'), 'hostids' => $hostIds, 'editable' => true, 'preservekeys' => true)); $this->validateHostsPermissions($hostIds, $dbHosts); $this->checkValidator($hostIds, new CHostNormalValidator(array('message' => _('Cannot update groups for discovered host "%1$s".')))); foreach ($dbHosts as $dbHost) { $oldGroupIds = zbx_objectValues($dbHost['groups'], 'groupid'); // check if host belongs to the removable host group $hostGroupIdsToRemove = array_intersect($data['groupids'], $oldGroupIds); if ($hostGroupIdsToRemove) { $objectIds[] = $dbHost['hostid']; foreach ($hostGroupIdsToRemove as $groupId) { $groupIdsToRemove[$groupId] = $groupId; } } } } if ($templateIds) { $dbTemplates = API::Template()->get(array('output' => array('templateid'), 'selectGroups' => array('groupid'), 'templateids' => $templateIds, 'editable' => true, 'preservekeys' => true)); $this->validateHostsPermissions($templateIds, $dbTemplates); foreach ($dbTemplates as $dbTemplate) { $oldGroupIds = zbx_objectValues($dbTemplate['groups'], 'groupid'); // check if template belongs to the removable host group $templateGroupIdsToRemove = array_intersect($data['groupids'], $oldGroupIds); if ($templateGroupIdsToRemove) { $objectIds[] = $dbTemplate['templateid']; foreach ($templateGroupIdsToRemove as $groupId) { $groupIdsToRemove[$groupId] = $groupId; } } } } if ($groupIdsToRemove) { if (!$this->isWritable($groupIdsToRemove)) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } // check if host group can be removed from given hosts and templates leaving them with at least one more host group $unlinkableObjectIds = getUnlinkableHostIds($groupIdsToRemove, $objectIds); if (count($objectIds) != count($unlinkableObjectIds)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('One of the objects is left without a host group.')); } } }
function getDeletableHostGroupIds(array $groupIds) { // selecting the list of hosts linked to the host groups $dbResult = DBselect('SELECT hg.hostid' . ' FROM hosts_groups hg' . ' WHERE ' . dbConditionInt('hg.groupid', $groupIds)); $linkedHostIds = array(); while ($dbRow = DBfetch($dbResult)) { $linkedHostIds[] = $dbRow['hostid']; } // the list of hosts which can be unlinked from the host groups $hostIds = getUnlinkableHostIds($groupIds, $linkedHostIds); $dbResult = DBselect('SELECT g.groupid' . ' FROM groups g' . ' WHERE g.internal=' . ZBX_NOT_INTERNAL_GROUP . ' AND ' . dbConditionInt('g.groupid', $groupIds) . ' AND NOT EXISTS (' . 'SELECT NULL' . ' FROM hosts_groups hg' . ' WHERE g.groupid=hg.groupid' . ($hostIds ? ' AND ' . dbConditionInt('hg.hostid', $hostIds, true) : '') . ')'); $deletableGroupIds = array(); while ($dbRow = DBfetch($dbResult)) { $deletableGroupIds[$dbRow['groupid']] = $dbRow['groupid']; } return $deletableGroupIds; }
/** * Update host groups with new hosts (rewrite). * * @param array $data * @param array $data['groups'] * @param array $data['hosts'] * @param array $data['templates'] * * @return array */ public function massUpdate(array $data) { $groupIds = array_unique(zbx_objectValues(zbx_toArray($data['groups']), 'groupid')); $hostIds = array_unique(zbx_objectValues(isset($data['hosts']) ? zbx_toArray($data['hosts']) : null, 'hostid')); $templateIds = array_unique(zbx_objectValues(isset($data['templates']) ? zbx_toArray($data['templates']) : null, 'templateid')); $workHostIds = array(); // validate permission $allowedGroups = $this->get(array('output' => array('groupid'), 'groupids' => $groupIds, 'editable' => true, 'preservekeys' => true)); foreach ($groupIds as $groupId) { if (!isset($allowedGroups[$groupId])) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } } // validate allowed hosts if (!empty($hostIds)) { if (!API::Host()->isWritable($hostIds)) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } // check if any of the hosts are discovered $this->checkValidator($hostIds, new CHostNormalValidator(array('message' => _('Cannot update groups for discovered host "%1$s".')))); $workHostIds = zbx_toHash($hostIds); } // validate allowed templates if (!empty($templateIds)) { $allowedTemplates = API::Template()->get(array('output' => array('templateid'), 'templateids' => $templateIds, 'editable' => true, 'preservekeys' => true)); foreach ($templateIds as $templateId) { if (!isset($allowedTemplates[$templateId])) { self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); } $workHostIds[$templateId] = $templateId; } } // get old records // skip discovered hosts $oldRecords = DBfetchArray(DBselect('SELECT *' . ' FROM hosts_groups hg,hosts h' . ' WHERE ' . dbConditionInt('hg.groupid', $groupIds) . ' AND hg.hostid=h.hostid' . ' AND h.flags=' . ZBX_FLAG_DISCOVERY_NORMAL)); // calculate new records $replaceRecords = array(); $newRecords = array(); $hostIdsToValidate = array(); foreach ($groupIds as $groupId) { $groupRecords = array(); foreach ($oldRecords as $oldRecord) { if ($oldRecord['groupid'] == $groupId) { $groupRecords[] = $oldRecord; } } // find records for replace foreach ($groupRecords as $groupRecord) { if (isset($workHostIds[$groupRecord['hostid']])) { $replaceRecords[] = $groupRecord; } } // find records for create $groupHostIds = zbx_toHash(zbx_objectValues($groupRecords, 'hostid')); $newHostIds = array_diff($workHostIds, $groupHostIds); if ($newHostIds) { foreach ($newHostIds as $newHostId) { $newRecords[] = array('groupid' => $groupId, 'hostid' => $newHostId); } } // find records for delete $deleteHostIds = array_diff($groupHostIds, $workHostIds); if ($deleteHostIds) { foreach ($deleteHostIds as $deleteHostId) { $hostIdsToValidate[$deleteHostId] = $deleteHostId; } } } // validate hosts without groups if ($hostIdsToValidate) { $unlinkable = getUnlinkableHostIds($groupIds, $hostIdsToValidate); if (count($unlinkable) != count($hostIdsToValidate)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('One of the objects is left without a host group.')); } } // save DB::replace('hosts_groups', $oldRecords, array_merge($replaceRecords, $newRecords)); return array('groupids' => $groupIds); }