/** * 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); }