mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
4 Commits
feature/88
...
faf/quick_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf7a8cc42 | ||
|
|
726542dd66 | ||
|
|
8e65a65f6b | ||
|
|
f8ae1fd2d8 |
@@ -453,6 +453,11 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetTooltipAttributes($sClass)
|
||||
{
|
||||
return MetaModel::GetZListItems($sClass, 'list');
|
||||
}
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -474,7 +479,7 @@ class DisplayableNode extends GraphNode
|
||||
$sHtml .= '<hr/>';
|
||||
}
|
||||
$sHtml .= '<table><tbody>';
|
||||
foreach(MetaModel::GetZListItems($sSubClass, 'list') as $sAttCode)
|
||||
foreach(static::GetTooltipAttributes($sSubClass) as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSubClass, $sAttCode);
|
||||
$sHtml .= '<tr><td>'.$oAttDef->GetLabel().': </td><td>'.$oCurrObj->GetAsHtml($sAttCode).'</td></tr>';
|
||||
@@ -864,6 +869,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
*/
|
||||
public static function FromRelationGraph(RelationGraph $oGraph, $iGroupingThreshold = 20, $bDirectionDown = true, $bForPdf = false)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oNewGraph = new DisplayableGraph();
|
||||
$oNewGraph->bDirectionDown = $bDirectionDown;
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
@@ -1017,6 +1023,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
|
||||
$oKPI->ComputeStats('FromRelationGraph', '');
|
||||
return $oNewGraph;
|
||||
}
|
||||
|
||||
@@ -1027,6 +1034,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
*/
|
||||
public function InitFromGraphviz()
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sDot = $this->DumpAsXDot();
|
||||
if (strpos($sDot, 'digraph') === false)
|
||||
{
|
||||
@@ -1054,6 +1062,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeStats('InitFromGraphviz', '');
|
||||
}
|
||||
|
||||
public function GetBoundingBox()
|
||||
|
||||
@@ -203,6 +203,7 @@ class RelationEdge extends GraphEdge
|
||||
*/
|
||||
class RelationGraph extends SimpleGraph
|
||||
{
|
||||
private static bool $bOptimizationEnabled = true;
|
||||
protected $aSourceNodes; // Index of source nodes (for a quicker access)
|
||||
protected $aSinkNodes; // Index of sink nodes (for a quicker access)
|
||||
protected $aRedundancySettings; // Cache of user settings
|
||||
@@ -217,6 +218,16 @@ class RelationGraph extends SimpleGraph
|
||||
$this->aContextSearches = array();
|
||||
}
|
||||
|
||||
static public function GetOptimizationEnabled(): bool
|
||||
{
|
||||
return static::$bOptimizationEnabled;
|
||||
}
|
||||
|
||||
static public function SetOptimizationEnabled(bool $bEnabled)
|
||||
{
|
||||
static::$bOptimizationEnabled = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object that will be the starting point for building the relations downstream
|
||||
*
|
||||
@@ -261,16 +272,23 @@ class RelationGraph extends SimpleGraph
|
||||
IssueLog::Error("Invalid context query '$sOQL'. A context query must contain at least two columns.");
|
||||
throw new Exception("Invalid context query '$sOQL'. A context query must contain at least two columns. Columns: ".implode(', ', $aAliases).'. ');
|
||||
}
|
||||
$aAliasNames = array_keys($aAliases);
|
||||
$oCondition = new BinaryExpression(new FieldExpression('id', $aAliasNames[0]), '=', new VariableExpression('id'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
if (!array_key_exists($sClass, $this->aContextSearches))
|
||||
{
|
||||
$this->aContextSearches[$sClass] = array();
|
||||
|
||||
if (static::GetOptimizationEnabled()) {
|
||||
$sClass = $oSearch->GetClass();
|
||||
$this->aContextSearches[$sClass][] = array('key' => $key, 'search' => $oSearch);
|
||||
}
|
||||
else {
|
||||
$aAliasNames = array_keys($aAliases);
|
||||
$oCondition = new BinaryExpression(new FieldExpression('id', $aAliasNames[0]), '=', new VariableExpression('id'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
if (!array_key_exists($sClass, $this->aContextSearches))
|
||||
{
|
||||
$this->aContextSearches[$sClass] = array();
|
||||
}
|
||||
$this->aContextSearches[$sClass][] = array('key' => $key, 'search' => $oSearch);
|
||||
}
|
||||
$this->aContextSearches[$sClass][] = array('key' => $key, 'search' => $oSearch);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,6 +301,8 @@ class RelationGraph extends SimpleGraph
|
||||
*/
|
||||
public function IsPartOfContext(DBObject $oObj, &$aRootCauses)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
$bRet = false;
|
||||
$sFinalClass = get_class($oObj);
|
||||
$aParentClasses = MetaModel::EnumParentClasses($sFinalClass, ENUM_PARENT_CLASSES_ALL);
|
||||
@@ -313,6 +333,7 @@ class RelationGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeStats(__METHOD__, get_class($oObj));
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
@@ -329,6 +350,7 @@ class RelationGraph extends SimpleGraph
|
||||
*/
|
||||
public function ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy, $aUnreachableObjects = array())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
//echo "<h5>Sources only...</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
// Build the graph out of the sources
|
||||
foreach ($this->aSourceNodes as $oSourceNode)
|
||||
@@ -336,8 +358,10 @@ class RelationGraph extends SimpleGraph
|
||||
$this->AddRelatedObjects($sRelCode, true, $oSourceNode, $iMaxDepth, $bEnableRedundancy);
|
||||
//echo "<h5>After processing of {$oSourceNode->GetId()}</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
}
|
||||
$oKPI->ComputeAndReport(__FUNCTION__.' - AddRelatedObjects');
|
||||
|
||||
// Mark the unreachable nodes
|
||||
$oKPI = new ExecutionKPI();
|
||||
foreach ($aUnreachableObjects as $oObj)
|
||||
{
|
||||
$sNodeId = RelationObjectNode::MakeId($oObj);
|
||||
@@ -347,29 +371,26 @@ class RelationGraph extends SimpleGraph
|
||||
$oNode->SetProperty('is_reached_allowed', false);
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeAndReport(__FUNCTION__.' - Mark unreachable nodes');
|
||||
|
||||
// Determine the reached nodes
|
||||
$oKPI = new ExecutionKPI();
|
||||
foreach ($this->aSourceNodes as $oSourceNode)
|
||||
{
|
||||
$oSourceNode->ReachDown('is_reached', true);
|
||||
//echo "<h5>After reaching from {$oSourceNode->GetId()}</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
}
|
||||
$oKPI->ComputeAndReport(__FUNCTION__.' - Determine reached nodes');
|
||||
|
||||
// Mark also the "context" nodes as reached and record the "root causes" for each node
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$aRootCauses = array();
|
||||
if (!is_null($oObj) && $this->IsPartOfContext($oObj, $aRootCauses))
|
||||
{
|
||||
$oNode->SetProperty('context_root_causes', $aRootCauses);
|
||||
$oNode->ReachDown('is_reached', true);
|
||||
}
|
||||
}
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->MarkContextNodesAsReached();
|
||||
$oKPI->ComputeAndReport(__FUNCTION__.' - Mark context nodes as reached');
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
if ( MetaModel::GetConfig()->Get('relations.complete_analysis')) {
|
||||
$this->ApplyUserRightsOnGraph();
|
||||
}
|
||||
$oKPI->ComputeAndReport(__FUNCTION__.' - Apply user rights on graph');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,6 +405,7 @@ class RelationGraph extends SimpleGraph
|
||||
*/
|
||||
public function ComputeRelatedObjectsUp($sRelCode, $iMaxDepth, $bEnableRedundancy)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
//echo "<h5>Sinks only...</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
// Build the graph out of the sinks
|
||||
foreach ($this->aSinkNodes as $oSinkNode)
|
||||
@@ -407,6 +429,7 @@ class RelationGraph extends SimpleGraph
|
||||
if ( MetaModel::GetConfig()->Get('relations.complete_analysis')) {
|
||||
$this->ApplyUserRightsOnGraph();
|
||||
}
|
||||
$oKPI->ComputeStats('GetRelatedObjects-Up', '');
|
||||
}
|
||||
|
||||
|
||||
@@ -423,6 +446,11 @@ class RelationGraph extends SimpleGraph
|
||||
*/
|
||||
protected function AddRelatedObjects($sRelCode, $bDown, $oObjectNode, $iMaxDepth, $bEnableRedundancy)
|
||||
{
|
||||
if (static::GetOptimizationEnabled()) {
|
||||
$this->AddRelatedObjects_Optimized();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($iMaxDepth > 0)
|
||||
{
|
||||
if ($oObjectNode instanceof RelationRedundancyNode)
|
||||
@@ -513,6 +541,64 @@ class RelationGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
|
||||
public function AddRelatedObjects_Optimized()
|
||||
{
|
||||
$sRelCode = 'impact';
|
||||
|
||||
// TODO : dehardcode against the source nodes
|
||||
$sSQLQuery = file_get_contents(APPROOT.'/impact_server1.sql');
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSQLQuery, MYSQLI_ASSOC);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aClassToId = [];
|
||||
foreach ($aRes as $aRow) {
|
||||
if (is_null($aRow['parent_class']) || is_null($aRow['parent_id'])) {
|
||||
// No parent => source node already present in the graph
|
||||
continue;
|
||||
}
|
||||
$aClassToId[$aRow['class']][$aRow['id']] = $aRow['name'];
|
||||
}
|
||||
$oKPI->ComputeAndReport('AddRelatedObjectsDown - Create aClassToId');
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
// One query per class => not too bad
|
||||
// Note: it is not possible to use the root class as we need to load the tooltip attributes
|
||||
foreach ($aClassToId as $sClass => $aIds) {
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AllowAllData();
|
||||
$oSearch->AddCondition('id', array_keys($aIds), 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => DisplayableNode::GetTooltipAttributes($sClass)]);
|
||||
while ($oObj = $oSet->Fetch()) {
|
||||
$sNodeId = RelationObjectNode::MakeId($oObj);
|
||||
if (!isset($this->aNodes[$sNodeId])) {
|
||||
$this->aNodes[$sNodeId] = new RelationObjectNode($this, $oObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeAndReport('AddRelatedObjectsDown - Query each class and create nodes: '.count($aClassToId));
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
foreach ($aRes as $aRow) {
|
||||
if (is_null($aRow['parent_class']) || is_null($aRow['parent_id'])) {
|
||||
// No parent, so no edge
|
||||
continue;
|
||||
}
|
||||
if ($aRow['backtracking'] == 0) {
|
||||
$oSourceNode = $this->GetNode("{$aRow['parent_class']}::{$aRow['parent_id']}");
|
||||
$oSinkNode = $this->GetNode("{$aRow['class']}::{$aRow['id']}");
|
||||
}
|
||||
else {
|
||||
$oSourceNode = $this->GetNode("{$aRow['class']}::{$aRow['id']}");
|
||||
$oSinkNode = $this->GetNode("{$aRow['parent_class']}::{$aRow['parent_id']}");
|
||||
}
|
||||
new RelationEdge($this, $oSourceNode, $oSinkNode);
|
||||
}
|
||||
$oKPI->ComputeAndReport('AddRelatedObjectsDown - Create edges : '.count($aRes));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if there is a redundancy (or use the existing one) and add the corresponding nodes/edges
|
||||
*
|
||||
@@ -747,4 +833,71 @@ class RelationGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark "context" nodes as reached and record the "root causes" for each node
|
||||
*/
|
||||
private function MarkContextNodesAsReached()
|
||||
{
|
||||
if (static::GetOptimizationEnabled()) {
|
||||
$this->MarkContextNodesAsReached_Optimized();
|
||||
return;
|
||||
}
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$aRootCauses = array();
|
||||
if (!is_null($oObj) && $this->IsPartOfContext($oObj, $aRootCauses))
|
||||
{
|
||||
$oNode->SetProperty('context_root_causes', $aRootCauses);
|
||||
$oNode->ReachDown('is_reached', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function MarkContextNodesAsReached_Optimized()
|
||||
{
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
// 1. Group all nodes by class
|
||||
$aClassToId = [];
|
||||
foreach ($oIterator as $oNode) {
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
if ($oObj) {
|
||||
$aClassToId[get_class($oObj)][$oObj->GetKey()] = $oNode;
|
||||
}
|
||||
}
|
||||
// 2. For each class, perform a search to find the context objects
|
||||
$aContextNodes = [];
|
||||
foreach ($aClassToId as $sClass => $aIdToNodes) {
|
||||
foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL) as $sParentClass)
|
||||
{
|
||||
if (!array_key_exists($sParentClass, $this->aContextSearches)) {
|
||||
continue; // No context search for this class
|
||||
}
|
||||
foreach ($this->aContextSearches[$sParentClass] as $aContextQuery)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
/** @var \DBSearch $oSearch */
|
||||
$oSearch = $aContextQuery['search']->DeepClone();
|
||||
$oSearch->AddCondition('id', array_keys($aIdToNodes), 'IN');
|
||||
$aAliasNames = array_keys($oSearch->GetSelectedClasses());
|
||||
$sObjectAlias = $aAliasNames[0];
|
||||
$sRootCauseAlias = $aAliasNames[1];
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oSet->OptimizeColumnLoad([$sObjectAlias => [], $sRootCauseAlias => []]);
|
||||
while($aRow = $oSet->FetchAssoc()) {
|
||||
$oRootCauseObject = $aRow[$sRootCauseAlias];
|
||||
if (is_null($oRootCauseObject)) continue;
|
||||
|
||||
$oNode = $aIdToNodes[$aRow[$sObjectAlias]->GetKey()];
|
||||
$aRootCauses = $oNode->GetProperty('context_root_causes', []);
|
||||
$aRootCauses[$aContextQuery['key']][$oRootCauseObject->GetKey()] = $oRootCauseObject;
|
||||
$oNode->SetProperty('context_root_causes', $aRootCauses);
|
||||
}
|
||||
$oKPI->ComputeStats('Query to find context objects', $sClass.' - '.$aContextQuery['key']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,8 +517,10 @@ EOF
|
||||
@fclose($rFile);
|
||||
$aOutput = array();
|
||||
$CommandLine = "\"$sDotExecutable\" -v -Tpng < \"$sDotFilePath\" -o\"$sImageFilePath\" 2>&1";
|
||||
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
exec($CommandLine, $aOutput, $iRetCode);
|
||||
$oKPI->ComputeStats('Graphviz execution png', 'png');
|
||||
if ($iRetCode != 0)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -573,8 +575,10 @@ EOF
|
||||
@fclose($rFile);
|
||||
$aOutput = array();
|
||||
$CommandLine = "\"$sDotExecutable\" -v -Tdot < \"$sDotFilePath\" -o\"$sXdotFilePath\" 2>&1";
|
||||
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
exec($CommandLine, $aOutput, $iRetCode);
|
||||
$oKPI->ComputeStats('Graphviz execution dot', 'dot');
|
||||
if ($iRetCode != 0)
|
||||
{
|
||||
$sHtml = '';
|
||||
|
||||
470
impact_server1.sql
Normal file
470
impact_server1.sql
Normal file
@@ -0,0 +1,470 @@
|
||||
-- Impact Analysis Query hardcoded for 'Server 1'
|
||||
WITH RECURSIVE related_impacts(name, class, id, parent_class, parent_id, redundancy, backtracking) as (
|
||||
/* Anchor query */
|
||||
SELECT DISTINCT IF((`SOURCE`.`finalclass` IN ('Middleware', 'DBServer', 'WebServer', 'PCSoftware', 'OtherSoftware')), CAST(CONCAT(COALESCE(`SOURCE`.`name`, ''), COALESCE(' ', ''), COALESCE(`FunctionalCI_system_id`.`name`, '')) AS CHAR), CAST(CONCAT(COALESCE(`SOURCE`.`name`, '')) AS CHAR)) AS `name`,
|
||||
`SOURCE`.`finalclass` AS `class`,
|
||||
`SOURCE`.`id` AS `id`,
|
||||
CAST(null AS CHAR(255)) AS `parent_class`,
|
||||
CAST(null AS UNSIGNED) AS `parent_id`,
|
||||
CAST(null AS CHAR(250)) AS `redundancy`,
|
||||
CAST(0 AS UNSIGNED) AS `backtracking`
|
||||
FROM
|
||||
`functionalci` AS `SOURCE`
|
||||
LEFT JOIN (
|
||||
`softwareinstance` AS `SOURCE_poly_SoftwareInstance`
|
||||
INNER JOIN
|
||||
`functionalci` AS `FunctionalCI_system_id`
|
||||
ON `SOURCE_poly_SoftwareInstance`.`functionalci_id` = `FunctionalCI_system_id`.`id`
|
||||
) ON `SOURCE`.`id` = `SOURCE_poly_SoftwareInstance`.`id`
|
||||
WHERE (`SOURCE`.`name` = 'Server1')
|
||||
|
||||
UNION DISTINCT
|
||||
/* Recursive part */
|
||||
(
|
||||
SELECT IF((`DOWN`.`finalclass` IN ('Team', 'Contact')), CAST(CONCAT(COALESCE(`DOWN`.`name`, '')) AS CHAR), CAST(CONCAT(COALESCE(`DOWN_poly_Person`.`first_name`, ''), COALESCE(' ', ''), COALESCE(`DOWN`.`name`, '')) AS CHAR)) AS `name`,
|
||||
`DOWN`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`functionalci` AS `UP`
|
||||
INNER JOIN (
|
||||
`contact` AS `DOWN`
|
||||
INNER JOIN
|
||||
`lnkcontacttofunctionalci` AS `lnk`
|
||||
ON `DOWN`.`id` = `lnk`.`contact_id`
|
||||
LEFT JOIN
|
||||
`person` AS `DOWN_poly_Person`
|
||||
ON `DOWN`.`id` = `DOWN_poly_Person`.`id`
|
||||
) ON (`lnk`.`functionalci_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('PhysicalDevice', 'ConnectableCI', 'DatacenterDevice', 'NetworkDevice', 'Server', 'ApplicationSolution', 'BusinessProcess', 'SoftwareInstance', 'Middleware', 'DBServer', 'WebServer', 'PCSoftware', 'OtherSoftware', 'MiddlewareInstance', 'DatabaseSchema', 'WebApplication', 'Rack', 'Enclosure', 'PowerConnection', 'PowerSource', 'PDU', 'TelephonyCI', 'Phone', 'MobilePhone', 'IPPhone', 'Tablet', 'PC', 'Printer', 'Peripheral', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'VirtualDevice', 'VirtualHost', 'Hypervisor', 'Farm', 'VirtualMachine', 'FunctionalCI')
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
CAST(CONCAT(COALESCE('redundancy=', ''), COALESCE(`DOWN`.`redundancy`, '')) AS CHAR) AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`functionalci` AS `UP`
|
||||
INNER JOIN (
|
||||
`applicationsolution` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
INNER JOIN
|
||||
`lnkapplicationsolutiontofunctionalci` AS `lnk`
|
||||
ON `DOWN`.`id` = `lnk`.`applicationsolution_id`
|
||||
) ON (`lnk`.`functionalci_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('PhysicalDevice', 'ConnectableCI', 'DatacenterDevice', 'NetworkDevice', 'Server', 'ApplicationSolution', 'BusinessProcess', 'SoftwareInstance', 'Middleware', 'DBServer', 'WebServer', 'PCSoftware', 'OtherSoftware', 'MiddlewareInstance', 'DatabaseSchema', 'WebApplication', 'Rack', 'Enclosure', 'PowerConnection', 'PowerSource', 'PDU', 'TelephonyCI', 'Phone', 'MobilePhone', 'IPPhone', 'Tablet', 'PC', 'Printer', 'Peripheral', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'VirtualDevice', 'VirtualHost', 'Hypervisor', 'Farm', 'VirtualMachine', 'FunctionalCI')
|
||||
WHERE 1
|
||||
UNION SELECT IF((`DOWN`.`finalclass` IN ('Middleware', 'DBServer', 'WebServer', 'PCSoftware', 'OtherSoftware')), CAST(CONCAT(COALESCE(`DOWN`.`name`, ''), COALESCE(' ', ''), COALESCE(`FunctionalCI_system_id`.`name`, '')) AS CHAR), CAST(CONCAT(COALESCE(`DOWN`.`name`, '')) AS CHAR)) AS `name`,
|
||||
`DOWN`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
1 AS `backtracking`
|
||||
FROM
|
||||
`applicationsolution` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN`
|
||||
INNER JOIN
|
||||
`lnkapplicationsolutiontofunctionalci` AS `lnk`
|
||||
ON `DOWN`.`id` = `lnk`.`functionalci_id`
|
||||
LEFT JOIN (
|
||||
`softwareinstance` AS `DOWN_poly_SoftwareInstance`
|
||||
INNER JOIN
|
||||
`functionalci` AS `FunctionalCI_system_id`
|
||||
ON `DOWN_poly_SoftwareInstance`.`functionalci_id` = `FunctionalCI_system_id`.`id`
|
||||
) ON `DOWN`.`id` = `DOWN_poly_SoftwareInstance`.`id`
|
||||
) ON (`lnk`.`applicationsolution_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'ApplicationSolution'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, ''), COALESCE(' ', ''), COALESCE(`FunctionalCI_system_id`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`functionalci` AS `UP`
|
||||
INNER JOIN (
|
||||
`softwareinstance` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `FunctionalCI_system_id`
|
||||
ON `DOWN`.`functionalci_id` = `FunctionalCI_system_id`.`id`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`functionalci_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('PhysicalDevice', 'ConnectableCI', 'DatacenterDevice', 'NetworkDevice', 'Server', 'ApplicationSolution', 'BusinessProcess', 'SoftwareInstance', 'Middleware', 'DBServer', 'WebServer', 'PCSoftware', 'OtherSoftware', 'MiddlewareInstance', 'DatabaseSchema', 'WebApplication', 'Rack', 'Enclosure', 'PowerConnection', 'PowerSource', 'PDU', 'TelephonyCI', 'Phone', 'MobilePhone', 'IPPhone', 'Tablet', 'PC', 'Printer', 'Peripheral', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'VirtualDevice', 'VirtualHost', 'Hypervisor', 'Farm', 'VirtualMachine', 'FunctionalCI')
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`applicationsolution` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
INNER JOIN
|
||||
`lnkapplicationsolutiontobusinessprocess` AS `lnk`
|
||||
ON `DOWN_FunctionalCI`.`id` = `lnk`.`businessprocess_id`
|
||||
) ON ((`lnk`.`applicationsolution_id` = `UP`.id) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('BusinessProcess')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'ApplicationSolution'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`middleware` AS `UP`
|
||||
INNER JOIN (
|
||||
`middlewareinstance` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`middleware_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'Middleware'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`dbserver` AS `UP`
|
||||
INNER JOIN (
|
||||
`databaseschema` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`dbserver_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'DBServer'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`webserver` AS `UP`
|
||||
INNER JOIN (
|
||||
`webapplication` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`webserver_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'WebServer'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`networkdevice` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
INNER JOIN
|
||||
`lnkconnectablecitonetworkdevice` AS `l1`
|
||||
ON `DOWN_FunctionalCI`.`id` = `l1`.`connectableci_id`
|
||||
) ON (((`l1`.`networkdevice_id` = `UP`.id) AND (`l1`.`type` = 'downlink')) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('DatacenterDevice', 'NetworkDevice', 'Server', 'PC', 'Printer', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'ConnectableCI')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'NetworkDevice'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`server` AS `UP`
|
||||
INNER JOIN (
|
||||
`hypervisor` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`server_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'Server'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`StorageSystem_storagesystem_id_FunctionalCI`.`name`, ''), COALESCE(' ', ''), COALESCE(`DOWN`.`name`, '')) AS CHAR) AS `name`,
|
||||
'LogicalVolume' AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`storagesystem` AS `UP`
|
||||
INNER JOIN (
|
||||
`logicalvolume` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `StorageSystem_storagesystem_id_FunctionalCI`
|
||||
ON `DOWN`.`storagesystem_id` = `StorageSystem_storagesystem_id_FunctionalCI`.`id`
|
||||
) ON ((`DOWN`.`storagesystem_id` = `UP`.id) AND COALESCE((`StorageSystem_storagesystem_id_FunctionalCI`.`finalclass` IN ('StorageSystem')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'StorageSystem'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`sanswitch` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
INNER JOIN
|
||||
`lnkdatacenterdevicetosan` AS `lnk`
|
||||
ON `DOWN_FunctionalCI`.`id` = `lnk`.`datacenterdevice_id`
|
||||
) ON ((`lnk`.`san_id` = `UP`.id) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('NetworkDevice', 'Server', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'DatacenterDevice')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'SANSwitch'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN`.`name`, '')) AS CHAR) AS `name`,
|
||||
'Tape' AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`tapelibrary` AS `UP`
|
||||
INNER JOIN
|
||||
`tape` AS `DOWN`
|
||||
ON (`DOWN`.`tapelibrary_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'TapeLibrary'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN`.`name`, '')) AS CHAR) AS `name`,
|
||||
'NASFileSystem' AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`nas` AS `UP`
|
||||
INNER JOIN
|
||||
`nasfilesystem` AS `DOWN`
|
||||
ON (`DOWN`.`nas_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'NAS'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
CAST(CONCAT(COALESCE('redundancy=', ''), COALESCE(`DOWN`.`redundancy`, '')) AS CHAR) AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`hypervisor` AS `UP`
|
||||
INNER JOIN (
|
||||
`farm` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`id` = `UP`.farm_id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'Hypervisor'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
1 AS `backtracking`
|
||||
FROM
|
||||
`farm` AS `UP`
|
||||
INNER JOIN (
|
||||
`hypervisor` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`farm_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'Farm'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`enclosure` AS `UP`
|
||||
INNER JOIN (
|
||||
`datacenterdevice` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`enclosure_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'Enclosure'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
CAST(CONCAT(COALESCE('redundancy=', ''), COALESCE(`DOWN`.`redundancy`, '')) AS CHAR) AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`powerconnection` AS `UP`
|
||||
INNER JOIN (
|
||||
`datacenterdevice` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON ((`DOWN`.`powera_id` = `UP`.id) OR (`DOWN`.`powerB_id` = `UP`.id))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('PowerSource', 'PDU', 'PowerConnection')
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
1 AS `backtracking`
|
||||
FROM
|
||||
`datacenterdevice` AS `UP`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON (((`DOWN_FunctionalCI`.`id` = `UP`.powerA_id) OR (`DOWN_FunctionalCI`.`id` = `UP`.powerB_id)) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('PowerSource', 'PDU', 'PowerConnection')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('NetworkDevice', 'Server', 'StorageSystem', 'SANSwitch', 'TapeLibrary', 'NAS', 'DatacenterDevice')
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`powerconnection` AS `UP`
|
||||
INNER JOIN (
|
||||
`pdu` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`powerstart_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('PowerSource', 'PDU', 'PowerConnection')
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`logicalvolume` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
INNER JOIN
|
||||
`lnkservertovolume` AS `lnk`
|
||||
ON `DOWN_FunctionalCI`.`id` = `lnk`.`server_id`
|
||||
) ON ((`lnk`.`volume_id` = `UP`.id) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('Server')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'LogicalVolume'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN_FunctionalCI`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`logicalvolume` AS `UP`
|
||||
INNER JOIN (
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
INNER JOIN
|
||||
`lnkvirtualdevicetovolume` AS `lnk`
|
||||
ON `DOWN_FunctionalCI`.`id` = `lnk`.`virtualdevice_id`
|
||||
) ON ((`lnk`.`volume_id` = `UP`.id) AND COALESCE((`DOWN_FunctionalCI`.`finalclass` IN ('VirtualHost', 'Hypervisor', 'Farm', 'VirtualMachine', 'VirtualDevice')), 1))
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class = 'LogicalVolume'
|
||||
WHERE 1
|
||||
UNION SELECT CAST(CONCAT(COALESCE(`DOWN_FunctionalCI`.`name`, '')) AS CHAR) AS `name`,
|
||||
`DOWN_FunctionalCI`.`finalclass` AS `class`,
|
||||
`DOWN`.`id` AS `id`,
|
||||
`FOUND`.`class` AS `parent_class`,
|
||||
`FOUND`.`id` AS `parent_id`,
|
||||
NULL AS `redundancy`,
|
||||
0 AS `backtracking`
|
||||
FROM
|
||||
`virtualhost` AS `UP`
|
||||
INNER JOIN (
|
||||
`virtualmachine` AS `DOWN`
|
||||
INNER JOIN
|
||||
`functionalci` AS `DOWN_FunctionalCI`
|
||||
ON `DOWN`.`id` = `DOWN_FunctionalCI`.`id`
|
||||
) ON (`DOWN`.`virtualhost_id` = `UP`.id)
|
||||
INNER JOIN
|
||||
`related_impacts` AS `FOUND`
|
||||
ON `UP`.id = `FOUND`.id AND `FOUND`.backtracking = 0 AND `FOUND`.class IN ('Hypervisor', 'Farm', 'VirtualHost')
|
||||
WHERE 1
|
||||
|
||||
)
|
||||
)
|
||||
SELECT name, class, id, parent_class, parent_id, redundancy, backtracking FROM related_impacts
|
||||
@@ -1862,6 +1862,7 @@ EOF
|
||||
}
|
||||
|
||||
// Remove excluded classes from the graph
|
||||
$oKPI = new ExecutionKPI();
|
||||
if (count($aExcludedClasses) > 0) {
|
||||
$oIterator = new RelationTypeIterator($oRelGraph, 'Node');
|
||||
foreach ($oIterator as $oNode) {
|
||||
@@ -1871,6 +1872,7 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeAndReport('Filtering nodes');
|
||||
|
||||
$oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
|
||||
$oGraph->InitFromGraphviz();
|
||||
|
||||
37
quick_impact_analysis.md
Normal file
37
quick_impact_analysis.md
Normal file
@@ -0,0 +1,37 @@
|
||||
An attempt to accelerate the process of impact analysis by relying on recursive queries
|
||||
|
||||
# TODO to prove the concept
|
||||
- [x] Integrate the recursive query into the process of building the impact graph
|
||||
- [x] Improve to cope with backtracking on redundancy nodes
|
||||
- [ ] Optimize context management
|
||||
- [x] Reduce the number of queries
|
||||
- [ ] See how to cache the queries (IN clause prevents caching)
|
||||
- [ ] Restore redundancy computation
|
||||
|
||||
# TODO to finalize the feature
|
||||
- [ ] Unit tests for the whole stuff
|
||||
- [ ] Deshardcode the query against the source nodes
|
||||
- [ ] Deshardcode the query against the datamodel
|
||||
- [ ] Get the algorithm from make_quick_impact_query.php
|
||||
- [ ] Find a clean way to hack queries
|
||||
- [ ] Eliminate the limitation on unions
|
||||
- [ ] Cache (parts of) the query
|
||||
- [ ] Review the KPIs
|
||||
- [ ] Decide if the legacy algorithm should be kept (opt-in/out)
|
||||
- [ ] Do not load persistent objects in the impact graph as they are not needed (tooltip loaded by ajax calls)
|
||||
|
||||
# Metrics
|
||||
|
||||
To to build the impact graph with 520 CIs
|
||||
|
||||
| Operation | Legacy | Optimized | Fix overhead in optimized version | Time per CI in optimized version |
|
||||
|---------------------|--------|-----------|-----------------------------------|------------------|
|
||||
| Build logical graph | 2.5 s | 0.4 s | 0 s | 0,7 ms |
|
||||
| Integrate context | 2 s | 0.8 s | 0,78 s | 0,1 ms |
|
||||
| Graphviz | 0.4 s | 0.4 s | 0,4 s | 0 ms |
|
||||
| Total | 4.9 s | 1.6 s | 1.18 s | 0,8 ms |
|
||||
|
||||
Comments:
|
||||
- Graphviz execution time is the time for Windows to spawn the process, so it is not really relevant
|
||||
- In the optimized version, building the logical graph still require to instantiate the objects which is done with one query per class, but it does not seem to be a must
|
||||
- For small graphs, the overhead on context queries can be questioned
|
||||
Reference in New Issue
Block a user