wip generate_dot

Former-commit-id: f41d5a55ec9cd8f27124d6697e92c5fb3009a2d2
This commit is contained in:
fbsanchez 2019-03-15 20:44:57 +01:00
parent 7e345035e1
commit fe045962e7
3 changed files with 476 additions and 17 deletions

View File

@ -31,6 +31,10 @@ global $config;
require_once $config['homedir'].'/include/functions_networkmap.php';
enterprise_include_once('include/functions_networkmap.php');
enterprise_include_once('include/functions_discovery.php');
// Avoid node overlapping.
define('GRAPHVIZ_RADIUS_CONVERSION_FACTOR', 20);
/**
* Manage networkmaps in Pandora FMS
@ -94,6 +98,13 @@ class NetworkMap
*/
public $nodes;
/**
* Useful to translate id_node to id_agent or id_module.
*
* @var array
*/
public $nodeMapping;
/**
* Relationship map.
*
@ -160,8 +171,8 @@ class NetworkMap
'x_offs' => 0,
'y_offs' => 0,
'z_dash' => 0.5,
'node_sep' => 0.1,
'rank_sep' => 0.1,
'node_sep' => 3,
'rank_sep' => 3,
'mindist' => 1,
'kval' => 0.1,
];
@ -341,7 +352,7 @@ class NetworkMap
if ($this->idTask) {
$recon_task = db_get_row_filter(
'trecon_task',
['id_rt' => $networkmap['source_data']]
['id_rt' => $this->idTask]
);
$this->network = $recon_task['subnet'];
}
@ -356,6 +367,34 @@ class NetworkMap
}
/**
* Retrieves node information using id_node as mapping instead element id.
*
* @param integer $id_node Target node.
* @param string $field Field to retrieve, if null, all are return.
*
* @return mixed Array (node data) or false if error.
*/
public function getNodeData(int $id_node, $field=null)
{
if (is_array($this->nodes) === false
|| is_array($this->nodeMapping) === false
) {
return false;
}
if (is_array($this->nodes[$this->nodeMapping[$id_node]]) === true) {
if (isset($field) === false) {
return $this->nodes[$this->nodeMapping[$id_node]];
} else {
return $this->nodes[$this->nodeMapping[$id_node]][$field];
}
} else {
return false;
}
}
/**
* Return nodes of current map.
*
@ -407,6 +446,112 @@ class NetworkMap
}
/**
* Search for nodes in current map definition.
*
* @return array Nodes detected, internal variable also updated.
*/
public function calculateNodes()
{
// Calculate.
if (!$this->nodes) {
// Search.
if ($this->idTask) {
// Network map, based on discovery task.
$this->nodes = enterprise_hook(
'get_discovery_agents',
[$this->idTask]
);
}
if ($this->network) {
// Network map, based on direct network.
$this->nodes = networkmap_get_new_nodes_from_ip_mask(
$this->network
);
} else if ($this->mapOptions['map_filter']['empty_map']) {
// Empty map returns no data.
$this->nodes = [];
} else {
// Group map.
$this->nodes = agents_get_agents(
$filter,
[
'id_grupo',
'nombre',
'id_os',
'id_parent',
'id_agente',
'normal_count',
'warning_count',
'critical_count',
'unknown_count',
'total_count',
'notinit_count',
],
'AR',
[
'field' => 'id_parent',
'order' => 'ASC',
]
);
}
}
return $this->nodes;
}
/**
* Search for relations for a given node in current map definition.
*
* @param array $node Origin.
* @param array $id_node Id for source node.
* @param array $id_source Id for source data, agent or module.
*
* @return array Relations found for given node.
*/
public function calculateRelations(
$node,
$id_node,
$id_source
) {
// Calculate.
if (is_array($node) === false) {
return false;
}
$relations = [];
if (isset($node['id_agente_modulo'])) {
// Module.
$relations = modules_get_relations(
[
'id_module' => $node['id_agente_modulo'],
]
);
}
if (isset($node['id_agente'])) {
// Agent.
$relations = modules_get_relations(
[
'id_agent' => $node['id_agente'],
]
);
if ($relations === false) {
$relations = [];
}
// Add also parent relationship.
$relations[$id_node] = $node['id_parent'];
}
// Others.
return $relations;
}
/**
* Generates or loads nodes&relations array from data load
* and stores it in $this->graph.
@ -474,6 +619,206 @@ class NetworkMap
}
/**
* Generates a graph definition (header only) for dot graph.
*
* @return string Dot graph header.
*/
public function openDotFile()
{
global $config;
$overlap = 'compress';
$map_filter = $this->mapOptions['map_filter'];
$nooverlap = $this->mapOptions['nooverlap'];
if (isset($config['networkmap_max_width'])) {
$size_x = ($config['networkmap_max_width'] / 100);
$size_y = ($size_x * 0.8);
} else {
$size_x = 8;
$size_y = 5.4;
$size = '';
}
if ($zoom > 0) {
$size_x *= $zoom;
$size_y *= $zoom;
}
$size = $size_x.','.$size_y;
if ($size_canvas === null) {
$size = ($this->mapOptions['size_canvas']['x'] / 100);
$size .= ','.($this->mapOptions['size_canvas']['y'] / 100);
}
// Graphviz custom values
if (isset($map_filter['node_sep'])) {
$node_sep = $map_filter['node_sep'];
} else {
$node_sep = 0.1;
}
if (isset($map_filter['rank_sep'])) {
$rank_sep = $map_filter['rank_sep'];
} else {
if ($layout == 'radial') {
$rank_sep = 1.0;
} else {
$rank_sep = 0.5;
}
}
if (isset($map_filter['mindist'])) {
$mindist = $map_filter['mindist'];
} else {
$mindist = 1.0;
}
if (isset($map_filter['kval'])) {
$kval = $map_filter['kval'];
} else {
$kval = 0.1;
}
// BEWARE: graphwiz DONT use single ('), you need double (").
$head = 'graph networkmap { dpi=100; bgcolor="transparent"; labeljust=l; margin=0; pad="0.75,0.75";';
if ($nooverlap != '') {
$head .= 'overlap=scale;';
$head .= 'outputorder=first;';
}
if ($layout == 'flat'
|| $layout == 'spring1'
|| $layout == 'spring2'
) {
if ($nooverlap != '') {
$head .= 'overlap="scalexy";';
}
if ($layout == 'flat') {
$head .= 'ranksep="'.$rank_sep.'";';
}
if ($layout == 'spring2') {
$head .= 'K="'.$kval.'";';
}
}
if ($layout == 'radial') {
$head .= 'ranksep="'.$rank_sep.'";';
}
if ($layout == 'circular') {
$head .= 'mindist="'.$mindist.'";';
}
$head .= 'ratio="fill";';
$head .= 'root=0;';
$head .= 'nodesep="'.$node_sep.'";';
$head .= 'size="'.$size.'";';
$head .= "\n";
return $head;
}
/**
* Creates a node in dot format.
* Requirements:
* id_node
* id_source
* status => defines 'color'
* label
* image
* url
*
* @param array $data Node definition.
*
* @return string Dot node.
*/
public function createDotNode($data)
{
global $config;
global $hack_networkmap_mobile;
$dot_str = '';
$color = COL_NORMAL;
$label = $data['label'];
$url = 'none';
$parent = $data['parent'];
$font_size = $this->mapOptions['font_size'];
$radius = $this->mapOptions['map_filter']['node_radius'];
$radius /= GRAPHVIZ_RADIUS_CONVERSION_FACTOR;
if (strlen($label) > 16) {
$label = ui_print_truncate_text($label, 16, false, true, false);
}
// If radius is 0, set to 1 instead.
if ($radius <= 0) {
$radius = 1;
}
// Simple node always. This kind of node is used only to
// retrieve X,Y positions from graphviz no for personalization.
$dot_str = $data['id_node'].' [ parent="'.$data['id_parent'].'"';
$dot_str .= ', color="'.$color.'", fontsize='.$font_size;
$dot_str .= ', shape="doublecircle"'.$url_node_link;
$dot_str .= ', style="filled", fixedsize=true, width='.$radius.', height='.$radius;
$dot_str .= ', label="'.$label.'", tooltip="'.$ajax_prefix;
$dot_str .= 'ajax.php?page=operation/agentes/ver_agente';
$dot_str .= '&get_agent_status_tooltip=1&id_agent='.$data['id_agente'];
$dot_str .= $meta_params.'"];'."\n";
return $dot_str;
}
/**
* Creates an edge in dot format.
* Requirements:
* from
* to
*
* @param array $data Edge content.
*
* @return string Dot code for given edge.
*/
public function createDotEdge($data)
{
if (is_array($data) === false) {
return '';
}
if (!isset($data['from']) || !isset($data['to'])) {
return '';
}
$edge = "\n".$data['from'].' -- '.$data['to'];
$edge .= '[len='.$this->mapOptions['map_filter']['rank_sep'];
$edge .= ', color="#BDBDBD", headclip=false, tailclip=false,';
$edge .= ' edgeURL=""];'."\n";
return $edge;
}
/**
* Returns dot file end string.
*
* @return string Dot file end string.
*/
public function closeDotFile()
{
return '}';
}
/**
* Generate a graphviz string structure to be used later.
*
@ -481,9 +826,65 @@ class NetworkMap
*/
public function generateDotGraph()
{
echo 'regenerar la net es: '.$this->network.'<br />';
if (!isset($this->dotGraph)) {
// Generate dot file.
$this->dotGraph = networkmap_generate_dot(
$nodes = [];
$edges = [];
$graph = '';
// Search for nodes.
$nodes = $this->calculateNodes();
// Search for relations.
// Build dot structure.
// Open Graph.
$graph = $this->openDotFile();
// Create dot nodes.
$i = 0;
foreach ($nodes as $k => $node) {
$this->nodeMapping[$i] = $k;
$graph .= $this->createDotNode(
[
'id_node' => $i,
'id_source' => $node['id_agente'],
'status' => agents_get_status_from_counts($node),
'label' => io_safe_output($node['alias']),
'image' => null,
'url' => 'none',
]
);
// Keep reverse reference.
$this->nodes[$k]['id_node'] = $i;
$edges[] = $this->calculateRelations($node, $i, $k);
// Increase for next node.
$i++;
}
hd($edges);
foreach ($edges as $rel) {
foreach ($rel as $from => $to) {
$graph .= $this->createDotEdge(
[
'from' => $from,
'to' => $this->nodes[$to]['id_node'],
]
);
}
}
// Create dot edges.
$graph .= $this->closeDotFile();
hd($graph);
$this->dotGraph = $graph;
/*
$this->dotGraph = networkmap_generate_dot(
get_product_name(),
$this->idGroup,
$this->mapOptions['simple'],
@ -508,7 +909,8 @@ class NetworkMap
null,
$this->mapOptions['old_mode'],
$this->mapOptions['map_filter']
);
);
*/
}
}
@ -554,10 +956,7 @@ class NetworkMap
include_once 'include/functions_os.php';
$map_filter = json_decode(
$this->map['filter'],
true
);
$map_filter = $this->mapOptions['map_filter'];
/*
* Let graphviz place the nodes.
@ -692,6 +1091,55 @@ class NetworkMap
$nodes_and_relations['nodes'][$index]['id'] = $node['id'];
$nodes_and_relations['nodes'][$index]['id_map'] = $this->idMap;
// Retrieve properties.
$node['id_agent'] = $this->getNodeData(
$node['id'],
'id_agente'
);
$node['id_module'] = $this->getNodeData(
$node['id'],
'id_agente_modulo'
);
// Specify node type and set values.
if (isset($node['id_agent']) === true) {
if (isset($node['id_module']) === false) {
// Agent.
$node['type'] = 'agent';
$node['source_data'] = $node['id_agent'];
$node['text'] = $this->getNodeData(
$node['id'],
'alias'
);
$node['image'] = ui_print_os_icon(
$this->getNodeData($node['id'], 'id_os'),
false,
true,
true,
true,
true,
true
);
} else if (isset($node['id_module'])) {
// Module.
$node['type'] = 'module';
$node['source_data'] = $node['id_module'];
$node['text'] = $this->getNodeData(
$node['id'],
'nombre'
);
$node['image'] = ui_print_moduletype_icon(
$this->getNodeData($node['id'], 'id_tipo_modulo'),
true,
true,
false,
true
);
}
}
$children_count = 0;
foreach ($relation_nodes as $relation) {
if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) {
@ -705,6 +1153,7 @@ class NetworkMap
}
}
// Center map over node with most children.
if (empty($node_center) || $node_center['counter'] < $children_count) {
$node_center['x'] = (int) $node['coords'][0];
$node_center['y'] = (int) $node['coords'][1];
@ -1509,7 +1958,9 @@ class NetworkMap
}
$networkmap = $this->map;
$networkmap['filter'] = json_decode($networkmap['filter'], true);
if (is_array($networkmap['filter']) === false) {
$networkmap['filter'] = json_decode($networkmap['filter'], true);
}
$networkmap['filter']['l2_network_interfaces'] = 1;

View File

@ -506,6 +506,12 @@ define('OPTION_COLOR_PICKER', 11);
define('NODE_TYPE', 0);
define('ARROW_TYPE', 1);
// Networkmap node types.
define('NODE_AGENT', 0);
define('NODE_MODULE', 1);
define('NODE_PANDORA', 2);
define('NODE_GENERIC', 3);
// SAML attributes constants.
define('SAML_ROLE_AND_TAG', 'eduPersonEntitlement');
define('SAML_USER_DESC', 'commonName');

View File

@ -489,11 +489,11 @@ function networkmap_generate_dot(
// Create void statistics array
$stats = [];
$count = 0;
$group_nodes = 10;
$graph .= networkmap_create_transparent_node($count);
foreach (array_keys($orphans) as $node) {
/*
$count = 0;
$group_nodes = 10;
$graph .= networkmap_create_transparent_node($count);
foreach (array_keys($orphans) as $node) {
if ($group_nodes == 0) {
$count++;
$graph .= networkmap_create_transparent_node($count);
@ -507,7 +507,8 @@ function networkmap_generate_dot(
);
$group_nodes--;
}
}
*/
// Create nodes
foreach ($nodes as $node_id => $node) {
@ -714,7 +715,7 @@ function networkmap_create_edge(
// Option edgeURL allows node navigation.
$edge = "\n".$head.' -- '.$tail;
$edge .= '[color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];';
$edge .= '[len='.$ranksep.', color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];';
$edge .= "\n";
return $edge;
@ -2306,6 +2307,7 @@ function networkmap_loadfile(
$relations_param[] = $row;
}
hd($networkmap_nodes);
return $networkmap_nodes;
}