Ejemplo n.º 1
0
function update_template_dependencies_for_host($hostid)
{
    $db_triggers = get_triggers_by_hostid($hostid);
    while ($trigger_data = DBfetch($db_triggers)) {
        $db_chd_triggers = get_triggers_by_templateid($trigger_data['triggerid']);
        while ($chd_trigger_data = DBfetch($db_chd_triggers)) {
            update_trigger($chd_trigger_data['triggerid'], NULL, NULL, NULL, NULL, NULL, NULL, NULL, replace_template_dependencies(get_trigger_dependencies_by_triggerid($trigger_data['triggerid']), $hostid), $trigger_data['triggerid']);
        }
    }
}
Ejemplo n.º 2
0
 /**
  * Links the templates to the given hosts.
  *
  * @param array $templateIds
  * @param array $targetIds		an array of host IDs to link the templates to
  *
  * @return array 	an array of added hosts_templates rows, with 'hostid' and 'templateid' set for each row
  */
 protected function link(array $templateIds, array $targetIds)
 {
     if (empty($templateIds)) {
         return;
     }
     // permission check
     if (!API::Template()->isReadable($templateIds)) {
         self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
     }
     // check if someone passed duplicate templates in the same query
     $templateIdDuplicates = zbx_arrayFindDuplicates($templateIds);
     if (!zbx_empty($templateIdDuplicates)) {
         $duplicatesFound = [];
         foreach ($templateIdDuplicates as $value => $count) {
             $duplicatesFound[] = _s('template ID "%1$s" is passed %2$s times', $value, $count);
         }
         self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot pass duplicate template IDs for the linkage: %s.', implode(', ', $duplicatesFound)));
     }
     // get DB templates which exists in all targets
     $res = DBselect('SELECT * FROM hosts_templates WHERE ' . dbConditionInt('hostid', $targetIds));
     $mas = [];
     while ($row = DBfetch($res)) {
         if (!isset($mas[$row['templateid']])) {
             $mas[$row['templateid']] = [];
         }
         $mas[$row['templateid']][$row['hostid']] = 1;
     }
     $targetIdCount = count($targetIds);
     $commonDBTemplateIds = [];
     foreach ($mas as $templateId => $targetList) {
         if (count($targetList) == $targetIdCount) {
             $commonDBTemplateIds[] = $templateId;
         }
     }
     // check if there are any template with triggers which depends on triggers in templates which will be not linked
     $commonTemplateIds = array_unique(array_merge($commonDBTemplateIds, $templateIds));
     foreach ($templateIds as $templateid) {
         $triggerids = [];
         $dbTriggers = get_triggers_by_hostid($templateid);
         while ($trigger = DBfetch($dbTriggers)) {
             $triggerids[$trigger['triggerid']] = $trigger['triggerid'];
         }
         $sql = 'SELECT DISTINCT h.host' . ' FROM trigger_depends td,functions f,items i,hosts h' . ' WHERE (' . dbConditionInt('td.triggerid_down', $triggerids) . ' AND f.triggerid=td.triggerid_up' . ' )' . ' AND i.itemid=f.itemid' . ' AND h.hostid=i.hostid' . ' AND ' . dbConditionInt('h.hostid', $commonTemplateIds, true) . ' AND h.status=' . HOST_STATUS_TEMPLATE;
         if ($dbDepHost = DBfetch(DBselect($sql))) {
             $tmpTpls = API::Template()->get(['templateids' => $templateid, 'output' => API_OUTPUT_EXTEND]);
             $tmpTpl = reset($tmpTpls);
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger in template "%1$s" has dependency with trigger in template "%2$s".', $tmpTpl['host'], $dbDepHost['host']));
         }
     }
     $res = DBselect('SELECT ht.hostid,ht.templateid' . ' FROM hosts_templates ht' . ' WHERE ' . dbConditionInt('ht.hostid', $targetIds) . ' AND ' . dbConditionInt('ht.templateid', $templateIds));
     $linked = [];
     while ($row = DBfetch($res)) {
         if (!isset($linked[$row['hostid']])) {
             $linked[$row['hostid']] = [];
         }
         $linked[$row['hostid']][$row['templateid']] = 1;
     }
     // add template linkages, if problems rollback later
     $hostsLinkageInserts = [];
     foreach ($targetIds as $targetid) {
         foreach ($templateIds as $templateid) {
             if (isset($linked[$targetid]) && isset($linked[$targetid][$templateid])) {
                 continue;
             }
             $hostsLinkageInserts[] = ['hostid' => $targetid, 'templateid' => $templateid];
         }
     }
     DB::insert('hosts_templates', $hostsLinkageInserts);
     // check if all trigger templates are linked to host.
     // we try to find template that is not linked to hosts ($targetids)
     // and exists trigger which reference that template and template from ($templateids)
     $sql = 'SELECT DISTINCT h.host' . ' FROM functions f,items i,triggers t,hosts h' . ' WHERE f.itemid=i.itemid' . ' AND f.triggerid=t.triggerid' . ' AND i.hostid=h.hostid' . ' AND h.status=' . HOST_STATUS_TEMPLATE . ' AND NOT EXISTS (SELECT 1 FROM hosts_templates ht WHERE ht.templateid=i.hostid AND ' . dbConditionInt('ht.hostid', $targetIds) . ')' . ' AND EXISTS (SELECT 1 FROM functions ff,items ii WHERE ff.itemid=ii.itemid AND ff.triggerid=t.triggerid AND ' . dbConditionInt('ii.hostid', $templateIds) . ')';
     if ($dbNotLinkedTpl = DBfetch(DBSelect($sql, 1))) {
         self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger has items from template "%1$s" that is not linked to host.', $dbNotLinkedTpl['host']));
     }
     // check template linkage circularity
     $res = DBselect('SELECT ht.hostid,ht.templateid' . ' FROM hosts_templates ht,hosts h' . ' WHERE ht.hostid=h.hostid ' . ' AND h.status IN(' . HOST_STATUS_MONITORED . ',' . HOST_STATUS_NOT_MONITORED . ',' . HOST_STATUS_TEMPLATE . ')');
     // build linkage graph and prepare list for $rootList generation
     $graph = [];
     $hasParentList = [];
     $hasChildList = [];
     $all = [];
     while ($row = DBfetch($res)) {
         if (!isset($graph[$row['hostid']])) {
             $graph[$row['hostid']] = [];
         }
         $graph[$row['hostid']][] = $row['templateid'];
         $hasParentList[$row['templateid']] = $row['templateid'];
         $hasChildList[$row['hostid']] = $row['hostid'];
         $all[$row['templateid']] = $row['templateid'];
         $all[$row['hostid']] = $row['hostid'];
     }
     // get list of templates without parents
     $rootList = [];
     foreach ($hasChildList as $parentId) {
         if (!isset($hasParentList[$parentId])) {
             $rootList[] = $parentId;
         }
     }
     // search cycles and double linkages in rooted parts of graph
     $visited = [];
     foreach ($rootList as $root) {
         $path = [];
         // raise exception on cycle or double linkage
         $this->checkCircularAndDoubleLinkage($graph, $root, $path, $visited);
     }
     // there is still possible cycles without root
     if (count($visited) < count($all)) {
         self::exception(ZBX_API_ERROR_PARAMETERS, _('Circular template linkage is not allowed.'));
     }
     return $hostsLinkageInserts;
 }
Ejemplo n.º 3
0
function copy_template_triggers($hostid, $templateid = null, $copy_mode = false)
{
    if (null == $templateid) {
        $templateid = array_keys(get_templates_by_hostid($hostid));
    }
    if (is_array($templateid)) {
        foreach ($templateid as $id) {
            copy_template_triggers($hostid, $id, $copy_mode);
        }
        // attention recursion
        return;
    }
    $triggers = get_triggers_by_hostid($templateid);
    while ($trigger = DBfetch($triggers)) {
        copy_trigger_to_host($trigger['triggerid'], $hostid, $copy_mode);
    }
    update_template_dependencies_for_host($hostid);
}
Ejemplo n.º 4
0
 private static function link($templateids, $targetids)
 {
     if (empty($templateids)) {
         return true;
     }
     // check if any templates linked to targets have more than one unique item key\application {{{
     foreach ($targetids as $targetid) {
         $linkedTpls = self::get(array('nopermissions' => 1, 'output' => API_OUTPUT_SHORTEN, 'hostids' => $targetid));
         $allids = array_merge($templateids, zbx_objectValues($linkedTpls, 'templateid'));
         $sql = 'SELECT key_, count(*) as cnt ' . ' FROM items ' . ' WHERE ' . DBcondition('hostid', $allids) . ' GROUP BY key_ ' . ' HAVING count(*) > 1';
         $res = DBselect($sql);
         if ($db_cnt = DBfetch($res)) {
             self::exception(ZBX_API_ERROR_PARAMETERS, S_TEMPLATE_WITH_ITEM_KEY . ' [' . htmlspecialchars($db_cnt['key_']) . '] ' . S_ALREADY_LINKED_TO_HOST_SMALL);
         }
         $sql = 'SELECT name, count(*) as cnt ' . ' FROM applications ' . ' WHERE ' . DBcondition('hostid', $allids) . ' GROUP BY name ' . ' HAVING count(*) > 1';
         $res = DBselect($sql);
         if ($db_cnt = DBfetch($res)) {
             self::exception(ZBX_API_ERROR_PARAMETERS, S_TEMPLATE_WITH_APPLICATION . ' [' . htmlspecialchars($db_cnt['name']) . '] ' . S_ALREADY_LINKED_TO_HOST_SMALL);
         }
     }
     // }}} check if any templates linked to targets have more than one unique item key\application
     // CHECK TEMPLATE TRIGGERS DEPENDENCIES {{{
     foreach ($templateids as $tnum => $templateid) {
         $triggerids = array();
         $db_triggers = get_triggers_by_hostid($templateid);
         while ($trigger = DBfetch($db_triggers)) {
             $triggerids[$trigger['triggerid']] = $trigger['triggerid'];
         }
         $sql = 'SELECT DISTINCT h.host ' . ' FROM trigger_depends td, functions f, items i, hosts h ' . ' WHERE (' . DBcondition('td.triggerid_down', $triggerids) . ' AND f.triggerid=td.triggerid_up) ' . ' AND i.itemid=f.itemid ' . ' AND h.hostid=i.hostid ' . ' AND ' . DBcondition('h.hostid', $templateids, true) . ' AND h.status=' . HOST_STATUS_TEMPLATE;
         if ($db_dephost = DBfetch(DBselect($sql))) {
             $options = array('templateids' => $templateid, 'output' => API_OUTPUT_EXTEND);
             $tmp_tpls = self::get($options);
             $tmp_tpl = reset($tmp_tpls);
             self::exception(ZBX_API_ERROR_PARAMETERS, 'Trigger in template [ ' . $tmp_tpl['host'] . ' ] has dependency with trigger in template [ ' . $db_dephost['host'] . ' ]');
         }
     }
     // }}} CHECK TEMPLATE TRIGGERS DEPENDENCIES
     $linked = array();
     $sql = 'SELECT hostid, templateid ' . ' FROM hosts_templates ' . ' WHERE ' . DBcondition('hostid', $targetids) . ' AND ' . DBcondition('templateid', $templateids);
     $linked_db = DBselect($sql);
     while ($pair = DBfetch($linked_db)) {
         $linked[] = array($pair['hostid'] => $pair['templateid']);
     }
     // add template linkages, if problems rollback later
     foreach ($targetids as $targetid) {
         foreach ($templateids as $tnum => $templateid) {
             foreach ($linked as $lnum => $link) {
                 if (isset($link[$targetid]) && $link[$targetid] == $templateid) {
                     continue 2;
                 }
             }
             $values = array(get_dbid('hosts_templates', 'hosttemplateid'), $targetid, $templateid);
             $sql = 'INSERT INTO hosts_templates VALUES (' . implode(', ', $values) . ')';
             $result = DBexecute($sql);
             if (!$result) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, 'DBError');
             }
         }
     }
     // CHECK CIRCULAR LINKAGE {{{
     // get template linkage graph
     $graph = array();
     $sql = 'SELECT ht.hostid, ht.templateid' . ' FROM hosts_templates ht, hosts h' . ' WHERE ht.hostid=h.hostid' . ' AND h.status=' . HOST_STATUS_TEMPLATE;
     $db_graph = DBselect($sql);
     while ($branch = DBfetch($db_graph)) {
         if (!isset($graph[$branch['hostid']])) {
             $graph[$branch['hostid']] = array();
         }
         $graph[$branch['hostid']][$branch['templateid']] = $branch['templateid'];
     }
     // get points that have more than one parent templates
     $start_points = array();
     $sql = 'SELECT max(ht.hostid) as hostid, ht.templateid' . ' FROM(' . ' SELECT count(htt.templateid) as ccc, htt.hostid' . ' FROM hosts_templates htt' . ' WHERE htt.hostid NOT IN ( SELECT httt.templateid FROM hosts_templates httt )' . ' GROUP BY htt.hostid' . ' ) ggg, hosts_templates ht' . ' WHERE ggg.ccc>1' . ' AND ht.hostid=ggg.hostid' . ' GROUP BY ht.templateid';
     $db_start_points = DBselect($sql);
     while ($start_point = DBfetch($db_start_points)) {
         $start_points[] = $start_point['hostid'];
         $graph[$start_point['hostid']][$start_point['templateid']] = $start_point['templateid'];
     }
     // add to the start points also points which we add current templates
     $start_points = array_merge($start_points, $targetids);
     $start_points = array_unique($start_points);
     foreach ($start_points as $spnum => $start) {
         $path = array();
         if (!self::checkCircularLink($graph, $start, $path)) {
             self::exception(ZBX_API_ERROR_PARAMETERS, S_CIRCULAR_LINK_CANNOT_BE_CREATED);
         }
     }
     // }}} CHECK CIRCULAR LINKAGE
     foreach ($targetids as $targetid) {
         foreach ($templateids as $tnum => $templateid) {
             foreach ($linked as $lnum => $link) {
                 if (isset($link[$targetid]) && $link[$targetid] == $templateid) {
                     unset($linked[$lnum]);
                     continue 2;
                 }
             }
             if (!sync_host_with_templates($targetid, $templateid)) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, S_CANNOT_SYNC_TEMPLATE);
             }
         }
     }
     return true;
 }
 /**
  * Links the templates to the given hosts.
  *
  * @param array $templateids
  * @param array $targetids    an array of host IDs to link the templates to
  *
  * @return bool
  */
 protected function link(array $templateids, array $targetids)
 {
     if (empty($templateids)) {
         return;
     }
     // check if someone passed duplicate templates in the same query
     $templateIdDuplicates = zbx_arrayFindDuplicates($templateids);
     if (!zbx_empty($templateIdDuplicates)) {
         $duplicatesFound = array();
         foreach ($templateIdDuplicates as $value => $count) {
             $duplicatesFound[] = _s('template ID "%1$s" is passed %2$s times', $value, $count);
         }
         self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot pass duplicate template IDs for the linkage: %s.', implode(', ', $duplicatesFound)));
     }
     // check if any templates linked to targets have more than one unique item key/application
     foreach ($targetids as $targetid) {
         $linkedTpls = $this->get(array('nopermissions' => true, 'output' => API_OUTPUT_SHORTEN, 'hostids' => $targetid));
         $allids = array_merge($templateids, zbx_objectValues($linkedTpls, 'templateid'));
         $res = DBselect('SELECT key_,COUNT(itemid) AS cnt' . ' FROM items' . ' WHERE ' . dbConditionInt('hostid', $allids) . ' GROUP BY key_' . ' HAVING COUNT(itemid)>1');
         if ($dbCnt = DBfetch($res)) {
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Template with item key "%1$s" already linked to host.', htmlspecialchars($dbCnt['key_'])));
         }
         $res = DBselect('SELECT name,COUNT(applicationid) AS cnt' . ' FROM applications' . ' WHERE ' . dbConditionInt('hostid', $allids) . ' GROUP BY name' . ' HAVING COUNT(applicationid)>1');
         if ($dbCnt = DBfetch($res)) {
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Template with application "%1$s" already linked to host.', htmlspecialchars($dbCnt['name'])));
         }
     }
     // get DB templates which exists in all targets
     $res = DBselect('SELECT * FROM hosts_templates WHERE ' . dbConditionInt('hostid', $targetids));
     $mas = array();
     while ($row = DBfetch($res)) {
         if (!isset($mas[$row['templateid']])) {
             $mas[$row['templateid']] = array();
         }
         $mas[$row['templateid']][$row['hostid']] = 1;
     }
     $targetIdCount = count($targetids);
     $commonDBTemplateIds = array();
     foreach ($mas as $templateId => $targetList) {
         if (count($targetList) == $targetIdCount) {
             $commonDBTemplateIds[] = $templateId;
         }
     }
     // check if there are any template with triggers which depends on triggers in templates which will be not linked
     $commonTemplateIds = array_unique(array_merge($commonDBTemplateIds, $templateids));
     foreach ($templateids as $templateid) {
         $triggerids = array();
         $dbTriggers = get_triggers_by_hostid($templateid);
         while ($trigger = DBfetch($dbTriggers)) {
             $triggerids[$trigger['triggerid']] = $trigger['triggerid'];
         }
         $sql = 'SELECT DISTINCT h.host' . ' FROM trigger_depends td,functions f,items i,hosts h' . ' WHERE (' . dbConditionInt('td.triggerid_down', $triggerids) . ' AND f.triggerid=td.triggerid_up)' . ' AND i.itemid=f.itemid' . ' AND h.hostid=i.hostid' . ' AND ' . dbConditionInt('h.hostid', $commonTemplateIds, true) . ' AND h.status=' . HOST_STATUS_TEMPLATE;
         if ($dbDepHost = DBfetch(DBselect($sql))) {
             $tmpTpls = API::Template()->get(array('templateids' => $templateid, 'output' => API_OUTPUT_EXTEND));
             $tmpTpl = reset($tmpTpls);
             self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger in template "%1$s" has dependency with trigger in template "%2$s".', $tmpTpl['host'], $dbDepHost['host']));
         }
     }
     $res = DBselect('SELECT hostid,templateid' . ' FROM hosts_templates' . ' WHERE ' . dbConditionInt('hostid', $targetids) . ' AND ' . dbConditionInt('templateid', $templateids));
     $linked = array();
     while ($row = DBfetch($res)) {
         if (!isset($linked[$row['hostid']])) {
             $linked[$row['hostid']] = array();
         }
         $linked[$row['hostid']][$row['templateid']] = 1;
     }
     // add template linkages, if problems rollback later
     foreach ($targetids as $targetid) {
         foreach ($templateids as $templateid) {
             if (isset($linked[$targetid]) && isset($linked[$targetid][$templateid])) {
                 continue;
             }
             $values = array(get_dbid('hosts_templates', 'hosttemplateid'), zbx_dbstr($targetid), zbx_dbstr($templateid));
             $sql = 'INSERT INTO hosts_templates VALUES (' . implode(', ', $values) . ')';
             $result = DBexecute($sql);
             if (!$result) {
                 self::exception(ZBX_API_ERROR_PARAMETERS, 'DBError');
             }
         }
     }
     // check if all trigger templates are linked to host.
     // we try to find template that is not linked to hosts ($targetids)
     // and exists trigger which reference that template and template from ($templateids)
     $sql = 'SELECT DISTINCT h.host' . ' FROM functions f,items i,triggers t,hosts h' . ' WHERE f.itemid=i.itemid' . ' AND f.triggerid=t.triggerid' . ' AND i.hostid=h.hostid' . ' AND h.status=' . HOST_STATUS_TEMPLATE . ' AND NOT EXISTS (SELECT 1 FROM hosts_templates ht WHERE ht.templateid=i.hostid AND ' . dbConditionInt('ht.hostid', $targetids) . ')' . ' AND EXISTS (SELECT 1 FROM functions ff,items ii WHERE ff.itemid=ii.itemid AND ff.triggerid=t.triggerid AND ' . dbConditionInt('ii.hostid', $templateids) . ')';
     if ($dbNotLinkedTpl = DBfetch(DBSelect($sql, 1))) {
         self::exception(ZBX_API_ERROR_PARAMETERS, _s('Trigger has items from template "%1$s" that is not linked to host.', $dbNotLinkedTpl['host']));
     }
     // check template linkage circularity
     $res = DBselect('SELECT ht.hostid,ht.templateid' . ' FROM hosts_templates ht,hosts h ' . ' WHERE ht.hostid=h.hostid ' . ' AND h.status IN(' . HOST_STATUS_MONITORED . ',' . HOST_STATUS_NOT_MONITORED . ',' . HOST_STATUS_TEMPLATE . ')');
     // build linkage graph and prepare list for $rootList generation
     $graph = array();
     $hasParentList = array();
     $hasChildList = array();
     $all = array();
     while ($row = DBfetch($res)) {
         if (!isset($graph[$row['hostid']])) {
             $graph[$row['hostid']] = array();
         }
         $graph[$row['hostid']][] = $row['templateid'];
         $hasParentList[$row['templateid']] = $row['templateid'];
         $hasChildList[$row['hostid']] = $row['hostid'];
         $all[$row['templateid']] = $row['templateid'];
         $all[$row['hostid']] = $row['hostid'];
     }
     // get list of templates without parents
     $rootList = array();
     foreach ($hasChildList as $parentId) {
         if (!isset($hasParentList[$parentId])) {
             $rootList[] = $parentId;
         }
     }
     // search cycles and double linkages in rooted parts of graph
     $visited = array();
     foreach ($rootList as $root) {
         $path = array();
         // raise exception on cycle or double linkage
         $this->checkCircularAndDoubleLinkage($graph, $root, $path, $visited);
     }
     // there is still possible cycles without root
     if (count($visited) < count($all)) {
         self::exception(ZBX_API_ERROR_PARAMETERS, _('Circular template linkage is not allowed.'));
     }
     // permission check
     if (!API::Host()->isWritable($targetids)) {
         self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
     }
     if (!API::Template()->isReadable($templateids)) {
         self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
     }
     // sync templates
     foreach ($targetids as $targetid) {
         foreach ($templateids as $templateid) {
             if (isset($linked[$targetid]) && isset($linked[$targetid][$templateid])) {
                 continue;
             }
             API::Application()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::DiscoveryRule()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::Itemprototype()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::Item()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
         }
         // we do linkage in two separate loops because for triggers you need all items already created on host
         foreach ($templateids as $templateid) {
             if (isset($linked[$targetid]) && isset($linked[$targetid][$templateid])) {
                 continue;
             }
             API::Trigger()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::TriggerPrototype()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::GraphPrototype()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
             API::Graph()->syncTemplates(array('hostids' => $targetid, 'templateids' => $templateid));
         }
     }
     foreach ($targetids as $targetid) {
         foreach ($templateids as $templateid) {
             if (isset($linked[$targetid]) && isset($linked[$targetid][$templateid])) {
                 continue;
             }
             API::Trigger()->syncTemplateDependencies(array('templateids' => $templateid, 'hostids' => $targetid));
         }
     }
 }