Commit 3b53f5e4 authored by Guillaume Lucas's avatar Guillaume Lucas
Browse files

[Centreon-GLPI|Webservices] Réécriture complète de l'import GLPI->Centreon

L'ancien code ne passe pas à l'échelle en fonction du nombre d'éléments
présents dans GLPI. En effet, on récupère tous les ordinateurs et tous les
équipements réseau. Pour chaque, on lance 2 requêtes (récupération IP et tags).
On fait des traitements simples et enfin, on ajoute. Évidemment, il faut
également prendre en compte le formatage/parsing SOAP qui n'est pas super rapide.

Solution :
  - déporter le travail en une seule fois sur le SGBD qui est conçu
pour ce type de travail ;
  - exporter le minimum d'informations ;
  - utiliser webservices uniquement pour le formatage SOAP des données
exportées.

Implémentation : une nouvelle méthode listObjectMonit() spécifique à notre
usage dans le plugin webservices de GLPI. Elle fait une requête SQL qui retourne
uniquement les informations utiles (nom, IP, tags) à Centreon en une seule fois.
Il faut également adapter Centreon-GLPI à ce changement.
parent 7032064d
......@@ -153,57 +153,27 @@ try {
/**
* Network Equipment
*/
$networkFilter = $filters;
$networkFilter['itemtype'] = 'NetworkEquipment';
$matchedResult = $glpiClient->listObjects($networkFilter);
$matchedResult = $glpiClient->listObjectsMonit($networkFilter);
foreach ($matchedResult as $result)
{
// On remonte l'IP d'administration de cet équipement réseau
$hostInfo = $glpiClient->getNetworkports(array('id' => $result['id'],
'itemtype' => 'NetworkEquipment'));
// On vérifie que l'IP remontée est valide
$address = "";
if (count($hostInfo)) {
foreach ($hostInfo as $info) {
if ($info['ip'] != "127.0.0.1") {
if (isset($ipRange) && $ipRange != "" && false == Centreon_Glpi_Utils::ipInRange($info['ip'], $ipRange)) {
continue;
} else {
$address = $info['ip'];
break;
}
}
}
}
/* On vérifie que l'IP de cet équipement n'est pas en dehors de la plage IP
éventuellement spécifiée par l'utilisateur dans l'interface web Centreon */
$IP_OFR = false;
if (isset($ipRange) && $ipRange != "" && false == Centreon_Glpi_Utils::ipInRange($result['ip'], $ipRange))
$IP_OFR = true;
// Gestion des tags remontés depuis GLPI qui indiquent les templates à utiliser
$tabTags = array();
$tabTags = $glpiClient->getTags(array('id' => $result['id'],
'itemtype' => 'NetworkEquipment'));
// On parcourt la structure particulière retournée par GLPI/Webservices
foreach ($tabTags as $ligneTags)
{
if (isset($ligneTags['tags']))
$listeTags = $ligneTags['tags'];
}
/* Si aucun tag n'est associé à cet équipement réseau, on prend celui
indiqué dans la règle d'import qui a matchée cet équipement */
if (!isset($listeTags) || empty($listeTags))
$listeTags = $hostTemplates[$ruleInfo['host_template_id']];
/* On vérifie la cohérence de la liste de tags.
Si un tag ne correspond pas à un template défini dans Centreon,
on s'arrête pour cet équipement : CLAPI le refusera */
on s'arrête pour cet équipement : CLAPI refusera son import */
$verifTemplate = true;
$tags = explode('|', $listeTags);
$tags = explode('|', $result['tags']);
foreach($tags as $tag)
{
if(!in_array($tag, $hostTemplates))
......@@ -215,9 +185,10 @@ try {
/* On ajoute cet équipement réseau à Centreon si il n'existe pas déjà (nom),
s'il a une adresse IP d'administration valide et si tous ses templates existent */
if (!isset($centreonHosts[$result['name']]) && !empty($address) && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a ADD -v \"".$result['name'].";".$result['name'].";".$address.";".$listeTags.";".$instances[$ruleInfo['instance_id']].";".implode("|", $hgs)."\"";
s'il a une adresse IP d'administration comprise dans la plage éventuellement spécifiée
et si tous ses templates existent */
if (!isset($centreonHosts[$result['name']]) && !$IP_OFR && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a ADD -v \"".$result['name'].";".$result['name'].";".$result['ip'].";".$result['tags'].";".$instances[$ruleInfo['instance_id']].";".implode("|", $hgs)."\"";
exec($clapiCommand);
exec($clapiCommandPrefix." -o HOST -a APPLYTPL -v ".$result['name']);
if (count($hcs)) {
......@@ -226,66 +197,42 @@ try {
exec($clapiCommand);
}
}
$centreonHosts[$result['name']] = $address;
$centreonHosts[$result['name']] = $result['ip'];
output("Added ".$result['name']." - (Rule: ".$ruleName.")");
$pollersToRestart[$ruleInfo['instance_id']] = $instances[$ruleInfo['instance_id']];
/* Si l'équipement existe déjà dans Centreon mais que son IP n'est pas la même que dans GLPI,
mais que ses templates sont valides, alors on met à jour l'IP de cet équipement */
} elseif (isset($centreonHosts[$result['name']]) && $centreonHosts[$result['name']] != $address && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a SETPARAM -v \"".$result['name'].";address;".$address."\"";
} elseif (isset($centreonHosts[$result['name']]) && $centreonHosts[$result['name']] != $result['ip'] && !$IP_OFR && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a SETPARAM -v \"".$result['name'].";address;".$result['ip']."\"";
exec($clapiCommand);
output("Updated IP address of ".$result['name']);
$pollersToRestart[$ruleInfo['instance_id']] = $instances[$ruleInfo['instance_id']];
}
}
/**
* Computers
* @todo refactor this
*/
$computerFilter = $filters;
$computerFilter['itemtype'] = 'Computer';
$matchedResult = $glpiClient->listObjects($computerFilter);
foreach ($matchedResult as $result) {
$hostInfo = $glpiClient->getNetworkports(array('id' => $result['id'],
'itemtype' => 'Computer'));
$address = "";
if (count($hostInfo)) {
foreach ($hostInfo as $info) {
if ($info['ip'] != "127.0.0.1") {
if (isset($ipRange) && $ipRange != "" && false == Centreon_Glpi_Utils::ipInRange($info['ip'], $ipRange)) {
continue;
} else {
$address = $info['ip'];
break;
}
}
}
}
// Gestion des tags remontés depuis GLPI qui indiquent les templates à utiliser
unset($listeTags);
$tabTags = array();
$tabTags = $glpiClient->getTags(array('id' => $result['id'],
'itemtype' => 'Computer'));
// On parcourt la structure particulière retournée par GLPI/Webservices
foreach ($tabTags as $ligneTags)
{
if (isset($ligneTags['tags']))
$listeTags = $ligneTags['tags'];
}
$matchedResult = $glpiClient->listObjectsMonit($computerFilter);
foreach ($matchedResult as $result)
{
/* On vérifie que l'IP de cet ordinateur n'est pas en dehors de la plage IP
éventuellement spécifiée par l'utilisateur dans l'interface web Centreon */
$IP_OFR = false;
if (isset($ipRange) && $ipRange != "" && false == Centreon_Glpi_Utils::ipInRange($result['ip'], $ipRange))
$IP_OFR = true;
/* Si aucun tag n'est associé à cet ordinateur, on prend celui
indiqué dans la règle d'import qui a matchée cet ordinateur */
if (!isset($listeTags) || empty($listeTags))
$listeTags = $hostTemplates[$ruleInfo['host_template_id']];
/* On vérifie la cohérence de la liste de tags.
Si un tag ne correspond pas à un template défini dans Centreon, on arrête là. */
$verifTemplate = true;
$tags = explode('|', $listeTags);
$tags = explode('|', $result['tags']);
foreach($tags as $tag)
{
if(!in_array($tag, $hostTemplates))
......@@ -297,9 +244,10 @@ try {
/* On ajoute cet ordinateur à Centreon s'il n'existe pas déjà (nom),
s'il a une adresse IP d'administration valide et si tous ses templates existent */
if (!isset($centreonHosts[$result['name']]) && $address && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a ADD -v \"".$result['name'].";".$result['name'].";".$address.";".$listeTags.";".$instances[$ruleInfo['instance_id']].";".implode("|", $hgs)."\"";
s'il a une adresse IP d'administration comprise dans la plage éventuellement spécifiée
et si tous ses templates existent */
if (!isset($centreonHosts[$result['name']]) && !$IP_OFR && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a ADD -v \"".$result['name'].";".$result['name'].";".$result['ip'].";".$result['tags'].";".$instances[$ruleInfo['instance_id']].";".implode("|", $hgs)."\"";
exec($clapiCommand);
exec($clapiCommandPrefix." -o HOST -a APPLYTPL -v ".$result['name']);
if (count($hcs)) {
......@@ -308,13 +256,13 @@ try {
exec($clapiCommand);
}
}
$centreonHosts[$result['name']] = $address;
$centreonHosts[$result['name']] = $result['ip'];
output("Added ".$result['name']." - (Rule: ".$ruleName.")");
$pollersToRestart[$ruleInfo['instance_id']] = $instances[$ruleInfo['instance_id']];
/* Si l'ordinateur existe déjà dans Centreon mais que son IP n'est pas la même que dans GLPI,
mais que ses templates sont valides, alors on met à jour l'IP de cet ordinateur */
} elseif (isset($centreonHosts[$result['name']]) && $centreonHosts[$result['name']] != $address && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a SETPARAM -v \"".$result['name'].";address;".$address."\"";
} elseif (isset($centreonHosts[$result['name']]) && $centreonHosts[$result['name']] != $result['ip'] && !$IP_OFR && $verifTemplate) {
$clapiCommand = $clapiCommandPrefix." -o HOST -a SETPARAM -v \"".$result['name'].";address;".$result['ip']."\"";
exec($clapiCommand);
output("Updated IP address of ".$result['name']);
$pollersToRestart[$ruleInfo['instance_id']] = $instances[$ruleInfo['instance_id']];
......
......@@ -127,8 +127,8 @@ function plugin_webservices_registerMethods() {
$WEBSERVICES_METHOD['glpi.setTicketAssign']
= array('PluginWebservicesMethodHelpdesk','methodsetTicketAssign');
// Remonter les tags dans Centreon
$WEBSERVICES_METHOD['glpi.getTags'] = array('PluginWebservicesMethodInventaire','methodGetTags');
// Remonter les machines dans Centreon
$WEBSERVICES_METHOD['glpi.listObjectsMonit'] = array('PluginWebservicesMethodInventaire','methodListObjectsMonit');
}
......
......@@ -1671,8 +1671,7 @@ class PluginWebservicesMethodInventaire extends PluginWebservicesMethodCommon {
LEFT JOIN `glpi_networknames` ON (`port`.`id` = `glpi_networknames`.`items_id`)
LEFT JOIN `glpi_ipaddresses` ON (`glpi_ipaddresses`.`items_id` = `glpi_networknames`.`id`)
WHERE port.itemtype = '".Toolbox::addslashes_deep($item_type)."'
AND port.items_id = '".Toolbox::cleanInteger($item_id)."'
AND logical_number = '1000'";
AND port.items_id = '".Toolbox::cleanInteger($item_id)."'";
if ($result = $DB->query($query)) {
while ($data = $DB->fetch_assoc($result))
......@@ -1721,70 +1720,230 @@ class PluginWebservicesMethodInventaire extends PluginWebservicesMethodCommon {
/**
* Get tags for an object for an authenticated user
* Get a list of objects
* for an authenticated user
* Adapted for centreon-glpi
*
* @param $params array of options (computer)
* @param protocol the commonication protocol used
*/
static function methodGetTags($params, $protocol)
{
global $DB;
* @param $params array of options
* @param $protocol the commonication protocol used
**/
static function methodListObjectsMonit($params, $protocol) {
global $DB, $CFG_GLPI;
if (isset($params['help'])) {
return array('start' => 'integer,optional',
'limit' => 'integer,optional',
'name' => 'string,optional',
'serial' => 'string,optional',
'otherserial' => 'string,optional',
'locations_id' => 'integer,optional',
'location_name' => 'string,optional',
'room' => 'string (Location only)',
'building' => 'string (Location only)',
'itemtype' => 'string,mandatory',
'show_label' => 'bool, optional (0 default)',
'help' => 'bool,optional');
}
$check = self::checkStandardParameters($params,$protocol);
if ($check != 1)
{
return array();
if (!Session::getLoginUserID()) {
return self::Error($protocol, WEBSERVICES_ERROR_NOTAUTHENTICATED);
}
//Must be superadmin to use this method
if(!Session::haveRight('config', 'w')){
return self::Error($protocol, WEBSERVICES_ERROR_NOTALLOWED);
}
if (!Session::haveRight("networking", "r")
|| !Session::haveRight("computer", "r"))
{
return array();
$resp = array();
$start = 0;
$limit = $_SESSION['glpilist_limit'];
if (isset($params['limit']) && is_numeric($params['limit'])) {
$limit = $params['limit'];
}
if (isset($params['start']) && is_numeric($params['start'])) {
$start = $params['start'];
}
foreach (array('show_label','show_name') as $key) {
$params[$key] = (isset($params[$key])?$params[$key]:false);
}
if (!isset($params['itemtype'])) {
return self::Error($protocol, WEBSERVICES_ERROR_MISSINGPARAMETER, '', 'itemtype');
}
if (!class_exists($params['itemtype'])) {
return self::Error($protocol, WEBSERVICES_ERROR_BADPARAMETER, '', 'itemtype');
}
$item = new $params['itemtype']();
$resp = array();
$output = array();
$params['return_fields'][$params['itemtype']] = array('name', 'ip', 'tags');
if ($item->can($params['data']['id'], 'r'))
{
$tags = array();
$query = "SELECT *
FROM `glpi_plugin_tags_tags` tags
WHERE tags.itemtype = '".Toolbox::addslashes_deep($params['itemtype'])."'
AND tags.items_id = '".Toolbox::addslashes_deep($params['id'])."'";
$output = array();
$item = new $params['itemtype'];
if (!$item->canView()) {
return self::Error($protocol, WEBSERVICES_ERROR_NOTALLOWED, '');
}
$table = $item->getTable();
//Restrict request
if ($item->isEntityAssign()) {
$where = getEntitiesRestrictRequest('WHERE', $table);
} else {
$where = "WHERE 1 ";
}
if ($item->maybeDeleted()) {
$where .= " AND `$table`.`is_deleted` = '0'";
}
if ($item->maybeTemplate()) {
$where .= " AND `$table`.`is_template` = '0'";
}
$left_join = "";
if ($item->getField('entities_id') != NOT_AVAILABLE) {
$left_join = " LEFT JOIN `glpi_entities`
ON (`$table`.`entities_id` = `glpi_entities`.`id`) ";
$already_joined = array();
$left_join.= self::listInventoryObjectsRequestLeftJoins($params, $item, $table, $already_joined).
getEntitiesRestrictRequest(" AND ", $table);
if ($result = $DB->query($query))
{
if ($ligne = $DB->fetch_assoc($result))
{
$tags[$ligne['id']] = $ligne;
$where = self::listInventoryObjectsRequestParameters($params, $item, $table, $where);
}
$resp = array();
$toformat = array('data' => $tags[$ligne['id']],
'searchOptions' => array('1' =>
array('table' => 'glpi_plugin_tags_tags',
'field' => 'tags',
'linkfield' => 'tags'
)
),
'options' => $params['options']);
$itemtype = $params['itemtype'];
parent::formatDataForOutput($toformat, $resp);
$output[$ligne['id']] = $resp;
}
/* On récupère les ports associés à un élément :
- si un port est tagué à la valeur 1000, on remonte uniquement ce port
- sinon, on remonte tous les ports associés à cet élément */
$left_join .= " INNER JOIN ( SELECT id, items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = '$itemtype'
AND items_id NOT IN (
SELECT items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = '$itemtype'
AND glpi_networkports.logical_number = '1000'
)
UNION DISTINCT
SELECT id, items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = '$itemtype'
AND glpi_networkports.logical_number = '1000'
) AS glpi_networkports
ON glpi_networkports.items_id = $table.id ";
}
}
/* Jointure de la table qui permet d'associer une ou plusieurs IP à un port ... */
$left_join .= " LEFT JOIN `glpi_networknames` ON (`glpi_networkports`.`id` = `glpi_networknames`.`items_id`)";
/* On récupére une seule IP non-nulle, qui n'est ni 0.0.0.0, ni 127.0.0.1 ni dans la réserve link-local v4 par port.
La première par ID. */
$left_join .= " INNER JOIN (SELECT items_id, name
FROM glpi_ipaddresses
WHERE name <> ''
AND name <> '0.0.0.0'
AND name <> '127.0.0.1'
AND name NOT LIKE '169.254.%'
GROUP BY items_id
) AS glpi_ipaddresses
ON `glpi_ipaddresses`.`items_id` = `glpi_networknames`.`id`";
/* On récupére les tags associés à l'élement. Il *doit* y avoir au moins un tag. */
$left_join .= " INNER JOIN `glpi_plugin_tags_tags` ON (`$table`.`id` = `glpi_plugin_tags_tags`.`items_id`)";
/* On ne récupére pas les machines qui ont un nom vide ... Plugin désinstalleur, toussa */
$where .= " AND `$table`.name <> ''
AND glpi_plugin_tags_tags.itemtype = '$itemtype'";
$query = "SELECT `$table`.name, glpi_ipaddresses.name AS ip, glpi_plugin_tags_tags.tags FROM `$table`
$left_join
$where
GROUP BY glpi_networkports.items_id
HAVING COUNT(glpi_networkports.items_id) = '1'
ORDER BY $table.name ASC
LIMIT $start,$limit";
/* Exemple de requête que le code ci-dessus va produire :
SELECT `glpi_networkequipments`.name, glpi_ipaddresses.name, glpi_plugin_tags_tags.tags
FROM `glpi_networkequipments`
LEFT JOIN `glpi_entities` ON (`glpi_networkequipments`.`entities_id` = `glpi_entities`.`id`) AND ( `glpi_networkequipments`.`entities_id` IN ('1') )
INNER JOIN ( SELECT id, items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = 'NetworkEquipment'
AND items_id NOT IN (
SELECT items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = 'NetworkEquipment'
AND glpi_networkports.logical_number = '1000'
)
UNION DISTINCT
SELECT id, items_id
FROM glpi_networkports
WHERE glpi_networkports.itemtype = 'NetworkEquipment'
AND glpi_networkports.logical_number = '1000'
) AS glpi_networkports
ON glpi_networkports.items_id = glpi_networkequipments.id
LEFT JOIN `glpi_networknames` ON (`glpi_networkports`.`id` = `glpi_networknames`.`items_id`)
INNER JOIN (SELECT items_id, name
FROM glpi_ipaddresses
WHERE name <> ''
AND name <> '0.0.0.0'
AND name <> '127.0.0.1'
AND name NOT LIKE '169.254.%'
GROUP BY items_id
) AS glpi_ipaddresses
ON `glpi_ipaddresses`.`items_id` = `glpi_networknames`.`id`
INNER JOIN `glpi_plugin_tags_tags` ON (`glpi_networkequipments`.`id` = `glpi_plugin_tags_tags`.`items_id`)
WHERE ( `glpi_networkequipments`.`entities_id` IN ('1') )
AND `glpi_networkequipments`.`is_deleted` = '0'
AND `glpi_networkequipments`.`is_template` = '0'
AND `glpi_networkequipments`.`name` LIKE '%%%'
AND `glpi_networkequipments`.name <> ''
AND glpi_plugin_tags_tags.itemtype = 'NetworkEquipment'
GROUP BY glpi_networkports.items_id
HAVING COUNT(glpi_networkports.items_id) = '1'
ORDER BY glpi_networkequipments.name ASC
LIMIT 0,1000000000;
Signification : on remonte uniquement le nom, l'IP et la liste de tags associés à un équipement réseau (ou à un ordinateur) si :
- Il a *exactement* une liste de tags (qui peut contenir qu'un seul tag, ce n'est pas un problème) ;
ET
- Il a *exactement* une IP valide. Valide = ni vide, ni 0.0.0.0 ni 127.0.0.1 ni dans la plage link-local v4
Ce dernier point implique que si une machine possède plusieurs interfaces réseau (port dans la terminologie GLPI),
il doit en rester une seule avec une seule IP sinon la machine n'est pas exportée. Cette discrimination se fait :
- Sur le fait de posséder une IP valide. Les ports qui n'en possèdent pas sont éliminés
- Sur le fait d'avoir un port dont le numéro est 1000. Positionné manuellement par l'utilisateur lors de l'entrée
de la machine dans l'inventaire, cela permet d'indiquer quelle est l'IP à remonter dans le cas où la machine
possède plusieurs ports avec une IP valide. */
foreach ($DB->request($query) as $data) {
$tmp = array();
$toformat = array('data' => $data,
'searchOptions' => array('1' => array('table' => "'$table'",
'field' => 'name',
'linkfield' => 'name'
),
'2' => array('table' => 'glpi_ipaddresses',
'field' => 'ip',
'linkfield' => 'ip'
),
'3' => array('table' => 'glpi_plugin_tags_tags',
'field' => 'tags',
'linkfield' => 'tags'
)
),
'options' => $params);
parent::formatDataForOutput($toformat, $tmp);
$output[] = $tmp;
}
return $output;
}
}
?>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment