From 4854d4b2df9d4a131a888b2f1d51bccf3c9e6075 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 29 Mar 2019 20:31:55 +0100
Subject: [PATCH 01/31] WIP atomic JS map

Former-commit-id: 95736d11295948e5dc20aefcf1293b7882729588
---
 .../include/class/NetworkMap.class.php        | 122 ++++++++++++------
 1 file changed, 82 insertions(+), 40 deletions(-)

diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index 17133d4d65..ecb92a59a7 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -34,9 +34,9 @@ enterprise_include_once('include/functions_networkmap.php');
 enterprise_include_once('include/functions_discovery.php');
 
 // Avoid node overlapping.
-define('GRAPHVIZ_RADIUS_CONVERSION_FACTOR', 20);
-define('MAP_X_CORRECTION', 600);
-define('MAP_Y_CORRECTION', 150);
+define('GRAPHVIZ_CONVERSION_FACTOR', 30);
+define('MAP_X_CORRECTION', 0);
+define('MAP_Y_CORRECTION', 0);
 
 
 /**
@@ -319,6 +319,8 @@ class NetworkMap
         // Default mapOptions values.
         // Defines the command to generate positions.
         $this->mapOptions['generation_method'] = LAYOUT_SPRING1;
+        // Use fixed positions defined (X,Y) per node.
+        $this->mapOptions['fixed_positions'] = 0;
         $this->mapOptions['width'] = $config['networkmap_max_width'];
         $this->mapOptions['height'] = $config['networkmap_max_width'];
         $this->mapOptions['simple'] = 0;
@@ -999,23 +1001,25 @@ class NetworkMap
             case NODE_GENERIC:
                 // Handmade ones.
                 // Add also parent relationship.
-                $parent_id = $node['id_parent'];
+                if (isset($node['id_parent'])) {
+                    $parent_id = $node['id_parent'];
 
-                if ((int) $parent_id > 0) {
-                    $parent_node = $this->getNodeData(
-                        (int) $parent_id,
-                        'id_node'
-                    );
-                }
+                    if ((int) $parent_id >= 0) {
+                        $parent_node = $this->getNodeData(
+                            (int) $parent_id,
+                            'id_node'
+                        );
+                    }
 
-                // Store relationship.
-                if ($parent_node) {
-                    $relations[] = [
-                        'id_parent'   => $parent_node,
-                        'parent_type' => NODE_GENERIC,
-                        'id_child'    => $node['id_node'],
-                        'child_type'  => NODE_GENERIC,
-                    ];
+                    // Store relationship.
+                    if ($parent_node !== null) {
+                        $relations[] = [
+                            'id_parent'   => $parent_node,
+                            'parent_type' => NODE_GENERIC,
+                            'id_child'    => $node['id_node'],
+                            'child_type'  => NODE_GENERIC,
+                        ];
+                    }
                 }
             break;
 
@@ -1233,8 +1237,13 @@ class NetworkMap
         $url = 'none';
         $parent = $data['parent'];
         $font_size = $this->mapOptions['font_size'];
-        $radius = $this->mapOptions['map_filter']['node_radius'];
-        $radius /= GRAPHVIZ_RADIUS_CONVERSION_FACTOR;
+        if (isset($data['radius'])) {
+            $radius = $data['radius'];
+        } else {
+            $radius = $this->mapOptions['map_filter']['node_radius'];
+        }
+
+        $radius /= GRAPHVIZ_CONVERSION_FACTOR;
 
         if (strlen($label) > 16) {
             $label = ui_print_truncate_text($label, 16, false, true, false);
@@ -1632,7 +1641,7 @@ class NetworkMap
                         $node[$k] = $v;
                     }
 
-                    $node['style']['label'] = $node['name'];
+                    $node['style']['label'] = $node['label'];
                     $node['style']['shape'] = 'circle';
                     $item['color'] = self::getColorByStatus($node['status']);
                 break;
@@ -1660,6 +1669,11 @@ class NetworkMap
                 $count_item_holding_area++;
             }
 
+            // Propagate styles.
+            foreach ($node['style'] as $k => $v) {
+                $item[$k] = $v;
+            }
+
             // Node image.
             $item['image_url'] = '';
             $item['image_width'] = 0;
@@ -1679,6 +1693,7 @@ class NetworkMap
             $item['text'] = io_safe_output($node['style']['label']);
             $item['shape'] = $node['style']['shape'];
             $item['map_id'] = $node['id_map'];
+
             if (!isset($node['style']['id_networkmap'])
                 || $node['style']['id_networkmap'] == ''
                 || $node['style']['id_networkmap'] == 0
@@ -1694,8 +1709,6 @@ class NetworkMap
                 $item['image'] = $item['image_url'];
                 $item['image_height'] = 52;
                 $item['image_width'] = 52;
-                $item['width'] = $this->mapOptions['map_filter']['node_radius'];
-                $item['height'] = $this->mapOptions['map_filter']['node_radius'];
             }
 
             $return[] = $item;
@@ -2148,8 +2161,8 @@ class NetworkMap
             if (preg_match('/^graph.*$/', $line) != 0) {
                 // Graph definition.
                 $fields = explode(' ', $line);
-                $this->map['width'] = ($fields[2] * 10 * GRAPHVIZ_RADIUS_CONVERSION_FACTOR);
-                $this->map['height'] = ($fields[3] * 10 * GRAPHVIZ_RADIUS_CONVERSION_FACTOR);
+                $this->map['width'] = ($fields[2] * GRAPHVIZ_CONVERSION_FACTOR);
+                $this->map['height'] = ($fields[3] * GRAPHVIZ_CONVERSION_FACTOR);
 
                 if ($this->map['width'] > $config['networkmap_max_width']) {
                     $this->map['width'] = $config['networkmap_max_width'];
@@ -2162,8 +2175,8 @@ class NetworkMap
                 // Node.
                 $fields = explode(' ', $line);
                 $id = $fields[1];
-                $nodes[$id]['x'] = (($fields[2] * $this->mapOptions['map_filter']['node_radius']) - $this->mapOptions['map_filter']['rank_sep'] * GRAPHVIZ_RADIUS_CONVERSION_FACTOR);
-                $nodes[$id]['y'] = (($fields[3] * $this->mapOptions['map_filter']['node_radius']) - $this->mapOptions['map_filter']['rank_sep'] * GRAPHVIZ_RADIUS_CONVERSION_FACTOR);
+                $nodes[$id]['x'] = ($fields[2] * GRAPHVIZ_CONVERSION_FACTOR);
+                $nodes[$id]['y'] = ($fields[3] * GRAPHVIZ_CONVERSION_FACTOR);
             } else if (preg_match('/^edge.*$/', $line) != 0
                 && empty($this->relations) === true
             ) {
@@ -2401,7 +2414,14 @@ class NetworkMap
          * Calculate X,Y positions.
          */
 
-        $graph = $this->calculateCoords();
+        if (!$this->mapOptions['fixed_positions']) {
+            $graph = $this->calculateCoords();
+        } else {
+            // Set by user.
+            $graph['nodes'] = $this->rawNodes;
+            $this->map['width'] = $this->mapOptions['width'];
+            $this->map['height'] = $this->mapOptions['height'];
+        }
 
         if (is_array($graph) === true) {
             $nodes = $graph['nodes'];
@@ -2501,6 +2521,10 @@ class NetworkMap
             $style['image'] = $node_tmp['image'];
             $style['width'] = $node_tmp['width'];
             $style['height'] = $node_tmp['height'];
+            $style['radius'] = max(
+                $style['width'],
+                $style['height']
+            );
             $style['label'] = $node_tmp['text'];
 
             $node_tmp['style'] = json_encode($style);
@@ -2676,6 +2700,7 @@ class NetworkMap
             $nodes = [];
         }
 
+        $this->nodes = $nodes;
         $nodes_js = $this->nodesToJS($nodes);
         $output .= 'networkmap.nodes = ('.json_encode($nodes_js).");\n";
 
@@ -2685,6 +2710,7 @@ class NetworkMap
             $relations = [];
         }
 
+        $this->relations = $relations;
         $links_js = $this->edgeToJS($relations);
         $output .= 'networkmap.links = ('.json_encode($links_js).");\n";
 
@@ -3220,17 +3246,25 @@ class NetworkMap
         if (enterprise_installed()
             && $this->useTooltipster
         ) {
+            $nodes_js = $this->nodesToJS($this->nodes);
+            $links_js = $this->edgeToJS($this->relations);
+
             $output .= '<script type="text/javascript">
-                var nodes = networkmap.nodes;
-                var arrows = networkmap.links;
-                var width = networkmap_dimensions[0];
-                var height = networkmap_dimensions[1];
-                var font_size = '.$this->mapOptions['font_size'].';
-                var custom_params = '.json_encode($this->tooltipParams).';
-                var controller = null;
-                var homedir = "'.ui_get_full_url(false).'"
                 $(function() {
-                    controller = new SimpleMapController("#simple_map");
+                    controller = new SimpleMapController({
+                        map_width: '.$this->map['width'].',
+                        map_height: '.$this->map['height'].',
+                        id: "'.$this->idMap.'",
+                        target: "#simple_map",
+                        nodes: '.json_encode($nodes_js).',
+                        arrows: '.json_encode($links_js).',
+                        center_x: '.$this->map['center_x'].',
+                        center_y: '.$this->map['center_y'].',
+                        z_dash: '.$this->map['filter']['z_dash'].',
+                        font_size: '.$this->mapOptions['font_size'].',
+                        homedir: "'.ui_get_full_url(false).'",
+                        custom_params: '.json_encode($this->tooltipParams).'
+                    });
                     controller.init_map();
                 });
             </script>';
@@ -3315,9 +3349,17 @@ class NetworkMap
 
             $output .= '<div id="simple_map" data-id="'.$this->idMap.'" ';
             $output .= 'style="border: 1px #ddd solid;';
-            $output .= ' width:'.$this->mapOptions['width'];
-            $output .= ' ;height:'.$this->mapOptions['height'].'">';
-            $output .= '<svg id="svg'.$this->idMap.'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" pointer-events="all" width="'.$this->mapOptions['width'].'" height="'.$this->mapOptions['height'].'px">';
+
+            if ($this->fullSize) {
+                $output .= ' width:100%';
+                $output .= ' ;height: 100%">';
+                $output .= '<svg id="svg'.$this->idMap.'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" pointer-events="all" width="100%" height="100%">';
+            } else {
+                $output .= ' width:'.$this->mapOptions['width'].'px';
+                $output .= ' ;height:'.$this->mapOptions['height'].'px">';
+                $output .= '<svg id="svg'.$this->idMap.'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" pointer-events="all" width="'.$this->mapOptions['width'].'" height="'.$this->mapOptions['height'].'px">';
+            }
+
             $output .= '</svg>';
             $output .= '</div>';
         } else {

From b0a6ea74151aa2901a3ff690f2b7db3c1f638b8c Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 29 Mar 2019 20:52:51 +0100
Subject: [PATCH 02/31] WIP atomic JS map. Minor fix to keep working

Former-commit-id: fee809008311942f1d9ad14aea70ba78e3d6eb3a
---
 .../include/class/NetworkMap.class.php        | 57 +++++++++++++------
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index ecb92a59a7..825ace8ae6 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -191,6 +191,20 @@ class NetworkMap
      */
     public $relations;
 
+    /**
+     * Private nodes converted to JS.
+     *
+     * @var array
+     */
+    private $nodesJS;
+
+    /**
+     * Private relations converted to JS.
+     *
+     * @var array
+     */
+    private $relationsJS;
+
     /**
      * Include a Pandora (or vendor) node or not.
      *
@@ -1604,6 +1618,11 @@ class NetworkMap
                 $node['style'] = json_decode($node['style'], true);
             }
 
+            // Propagate styles.
+            foreach ($node['style'] as $k => $v) {
+                $item[$k] = $v;
+            }
+
             $item['type'] = $node['type'];
             $item['fixed'] = true;
             $item['x'] = (int) $node['x'];
@@ -1643,7 +1662,13 @@ class NetworkMap
 
                     $node['style']['label'] = $node['label'];
                     $node['style']['shape'] = 'circle';
-                    $item['color'] = self::getColorByStatus($node['status']);
+                    if (isset($source_data['color'])) {
+                        $item['color'] = $source_data['color'];
+                    } else {
+                        $item['color'] = self::getColorByStatus(
+                            $node['status']
+                        );
+                    }
                 break;
             }
 
@@ -1669,11 +1694,6 @@ class NetworkMap
                 $count_item_holding_area++;
             }
 
-            // Propagate styles.
-            foreach ($node['style'] as $k => $v) {
-                $item[$k] = $v;
-            }
-
             // Node image.
             $item['image_url'] = '';
             $item['image_width'] = 0;
@@ -2700,9 +2720,13 @@ class NetworkMap
             $nodes = [];
         }
 
-        $this->nodes = $nodes;
-        $nodes_js = $this->nodesToJS($nodes);
-        $output .= 'networkmap.nodes = ('.json_encode($nodes_js).");\n";
+        $this->nodesJS = $this->nodesToJS($nodes);
+        $output .= 'networkmap.nodes = ('.json_encode($this->nodesJS).");\n";
+
+        // Clean.
+        unset($this->nodes);
+        unset($this->rawNodes);
+        unset($this->nodeMapping);
 
         // Translate edges to js links.
         $relations = $this->graph['relations'];
@@ -2710,9 +2734,11 @@ class NetworkMap
             $relations = [];
         }
 
-        $this->relations = $relations;
-        $links_js = $this->edgeToJS($relations);
-        $output .= 'networkmap.links = ('.json_encode($links_js).");\n";
+        $this->relationsJS = $this->edgeToJS($relations);
+        $output .= 'networkmap.links = ('.json_encode($this->relationsJS).");\n";
+
+        // Clean.
+        unset($this->relations);
 
         $output .= '
         ////////////////////////////////////////////////////////////////////
@@ -3246,9 +3272,6 @@ class NetworkMap
         if (enterprise_installed()
             && $this->useTooltipster
         ) {
-            $nodes_js = $this->nodesToJS($this->nodes);
-            $links_js = $this->edgeToJS($this->relations);
-
             $output .= '<script type="text/javascript">
                 $(function() {
                     controller = new SimpleMapController({
@@ -3256,8 +3279,8 @@ class NetworkMap
                         map_height: '.$this->map['height'].',
                         id: "'.$this->idMap.'",
                         target: "#simple_map",
-                        nodes: '.json_encode($nodes_js).',
-                        arrows: '.json_encode($links_js).',
+                        nodes: '.json_encode($this->nodesJS).',
+                        arrows: '.json_encode($this->relationsJS).',
                         center_x: '.$this->map['center_x'].',
                         center_y: '.$this->map['center_y'].',
                         z_dash: '.$this->map['filter']['z_dash'].',

From 11b2fbc2459f816bf4b560479b710ad8c97cf135 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Tue, 2 Apr 2019 16:25:29 +0200
Subject: [PATCH 03/31] WIP db

Former-commit-id: 3c231b9d90dc6c9fae5e7e398e829c8c28ffeed9
---
 pandora_console/extras/mr/27.sql              | 11 ++++++++++
 .../godmode/wizards/Wizard.main.php           |  7 ++++++-
 .../include/class/NetworkMap.class.php        |  1 +
 pandora_console/include/constants.php         | 20 +++++++++++++++++--
 pandora_console/pandoradb.sql                 |  1 +
 pandora_console/pandoradb_data.sql            |  7 +++----
 pandora_server/lib/PandoraFMS/Recon/Base.pm   |  8 +++++---
 7 files changed, 45 insertions(+), 10 deletions(-)
 create mode 100644 pandora_console/extras/mr/27.sql

diff --git a/pandora_console/extras/mr/27.sql b/pandora_console/extras/mr/27.sql
new file mode 100644
index 0000000000..5dc8a47d2f
--- /dev/null
+++ b/pandora_console/extras/mr/27.sql
@@ -0,0 +1,11 @@
+START TRANSACTION;
+
+ALTER TABLE `trecon_script` ADD COLUMN `type` int NOT NULL default 0;
+
+UPDATE trecon_script SET `type` = 1 WHERE `name`="Discovery.Application.VMware";
+UPDATE trecon_script SET `type` = 2 WHERE `name`="Discovery.Application.MySQL";
+UPDATE trecon_script SET `type` = 3 WHERE `name`="Discovery.Application.Oracle";
+UPDATE trecon_script SET `type` = 100 WHERE `name`="Discovery.Cloud";
+UPDATE trecon_script SET `type` = 101 WHERE `name`="Discovery.Cloud.RDS";
+
+COMMIT;
\ No newline at end of file
diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php
index 022402a8d1..d8a829e277 100644
--- a/pandora_console/godmode/wizards/Wizard.main.php
+++ b/pandora_console/godmode/wizards/Wizard.main.php
@@ -601,8 +601,13 @@ class Wizard
         }
 
         if (is_array($input['block_content']) === true) {
+            $label = '';
+            if (isset($input['label'])) {
+                $label = $input['label'];
+            }
+
             // Print independent block of inputs.
-            $output .= '<li id="'.$input['block_id'].'" class="'.$class.'">';
+            $output .= '<li id="'.$input['block_id'].'" class="'.$class.'">'.$label;
             $output .= '<ul class="wizard">';
             foreach ($input['block_content'] as $input) {
                 $output .= $this->printBlock($input, $return);
diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index 825ace8ae6..dba51499f4 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -2439,6 +2439,7 @@ class NetworkMap
         } else {
             // Set by user.
             $graph['nodes'] = $this->rawNodes;
+            $graph['relations'] = $this->relations;
             $this->map['width'] = $this->mapOptions['width'];
             $this->map['height'] = $this->mapOptions['height'];
         }
diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php
index ea18c90d3f..ceb48d1d0f 100644
--- a/pandora_console/include/constants.php
+++ b/pandora_console/include/constants.php
@@ -583,8 +583,24 @@ define('NETWORKMAP_DEFAULT_HEIGHT', 800);
 // Discovery task types.
 define('DISCOVERY_HOSTDEVICES', 0);
 define('DISCOVERY_HOSTDEVICES_CUSTOM', 1);
-define('DISCOVERY_CLOUD_AWS', 10);
-define('DISCOVERY_APP_VMWARE', 100);
+define('DISCOVERY_CLOUD_AWS', 2);
+define('DISCOVERY_APP_VMWARE', 3);
+define('DISCOVERY_APP_MYSQL', 4);
+define('DISCOVERY_APP_ORACLE', 5);
+define('DISCOVERY_CLOUD_AWS_EC2', 6);
+define('DISCOVERY_CLOUD_AWS_RDS', 7);
+
+
+// Discovery types matching definition.
+define('DISCOVERY_SCRIPT_HOSTDEVICES_CUSTOM', 0);
+// Standard applications.
+define('DISCOVERY_SCRIPT_APP_VMWARE', 1);
+define('DISCOVERY_SCRIPT_APP_MYSQL', 2);
+define('DISCOVERY_SCRIPT_APP_ORACLE', 3);
+// Cloud environments.
+define('DISCOVERY_SCRIPT_CLOUD_AWS', 100);
+define('DISCOVERY_SCRIPT_CLOUD_AWS_EC2', 101);
+define('DISCOVERY_SCRIPT_CLOUD_AWS_RDS', 102);
 
 // Discovery task descriptions.
 define('CLOUDWIZARD_AWS_DESCRIPTION', 'Discovery.Cloud.AWS.EC2');
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index 0ecc9b8f5d..d7c87538af 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -962,6 +962,7 @@ CREATE TABLE IF NOT EXISTS `trecon_script` (
 	`description` TEXT,
 	`script` varchar(250) default '',
 	`macros` TEXT,
+	`type` int NOT NULL default 0,
 	PRIMARY KEY  (`id_recon_script`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql
index ee4ad45c06..4e30bdef7e 100644
--- a/pandora_console/pandoradb_data.sql
+++ b/pandora_console/pandoradb_data.sql
@@ -1135,10 +1135,9 @@ INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (3, 'Monitoring&#x
 INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (4, 'Group&#x20;view', 'select&#x20;t1.nombre,&#x20;&#40;select&#x20;count&#40;t3.id_agente&#41;&#x20;from&#x20;tagente&#x20;as&#x20;t3&#x20;where&#x20;t1.id_grupo&#x20;=&#x20;t3.id_grupo&#41;&#x20;as&#x20;agents,&#x20;&#40;SELECT&#x20;COUNT&#40;t4.id_agente&#41;&#x20;FROM&#x20;tagente&#x20;as&#x20;t4&#x20;WHERE&#x20;t4.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;t4.disabled&#x20;=&#x20;0&#x20;AND&#x20;t4.ultimo_contacto&#x20;&lt;&#x20;NOW&#40;&#41;&#x20;-&#x20;&#40;intervalo&#x20;/&#x20;&#40;1/2&#41;&#41;&#41;&#x20;as&#x20;agent_unknown,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.id_agente&#x20;=&#x20;tagente_estado.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;utimestamp&#x20;&gt;&#x20;0&#x20;AND&#x20;tagente_modulo.id_tipo_modulo&#x20;NOT&#x20;IN&#40;21,22,23,24,100&#41;&#x20;AND&#x20;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&gt;=&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#41;&#x20;as&#x20;monitor_unknow,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.id_agente&#x20;=&#x20;tagente_estado.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_modulo.id_tipo_modulo&#x20;NOT&#x20;IN&#x20;&#40;21,22,23,24&#41;&#x20;AND&#x20;utimestamp&#x20;=&#x20;0&#41;&#x20;as&#x20;monitor_no_init,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_estado.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;estado&#x20;=&#x20;0&#x20;AND&#x20;&#40;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&lt;&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24,100&#41;&#41;&#41;&#x20;AND&#x20;&#40;utimestamp&#x20;&gt;&#x20;0&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24&#41;&#41;&#41;&#41;&#x20;as&#x20;monitor_ok,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_estado.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;estado&#x20;=&#x20;1&#x20;AND&#x20;&#40;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&lt;&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24,100&#41;&#41;&#41;&#x20;AND&#x20;utimestamp&#x20;&gt;&#x20;0&#41;&#x20;as&#x20;monitor_critical,&#x20;&#40;SELECT&#x20;COUNT&#40;talert_template_modules.id&#41;&#x20;FROM&#x20;talert_template_modules,&#x20;tagente_modulo,&#x20;tagente_estado,&#x20;tagente&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente_modulo.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;talert_template_modules.id_agent_module&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;times_fired&#x20;&gt;&#x20;0&#41;&#x20;as&#x20;monitor_alert_fired&#x20;from&#x20;tgrupo&#x20;as&#x20;t1&#x20;where&#x20;0&#x20;&lt;&#x20;&#40;select&#x20;count&#40;t2.id_agente&#41;&#x20;from&#x20;tagente&#x20;as&#x20;t2&#x20;where&#x20;t1.id_grupo&#x20;=&#x20;t2.id_grupo&#41;');
 
 -- trecon scripts
-INSERT INTO `trecon_script` VALUES (2,'IPMI&#x20;Recon','Specific&#x20;Pandora&#x20;FMS&#x20;Intel&#x20;DCM&#x20;Discovery&#x20;&#40;c&#41;&#x20;Artica&#x20;ST&#x20;2011&#x20;&lt;info@artica.es&gt;&#x0d;&#x0a;&#x0d;&#x0a;Usage:&#x20;./ipmi-recon.pl&#x20;&lt;task_id&gt;&#x20;&lt;group_id&gt;&#x20;&lt;create_incident_flag&gt;&#x20;&lt;custom_field1&gt;&#x20;&lt;custom_field2&gt;&#x20;&lt;custom_field3&gt;&#x20;&lt;custom_field4&gt;&#x0d;&#x0a;&#x0d;&#x0a;*&#x20;custom_field1&#x20;=&#x20;Network&#x20;i.e.:&#x20;192.168.100.0/24&#x0d;&#x0a;*&#x20;custom_field2&#x20;=&#x20;Username&#x0d;&#x0a;*&#x20;custom_field3&#x20;=&#x20;Password&#x0d;&#x0a;*&#x20;custom_field4&#x20;=&#x20;Additional&#x20;parameters&#x20;i.e.:&#x20;-D&#x20;LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.:&#x20;192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional&#x20;parameters\",\"help\":\"Optional&#x20;additional&#x20;parameters&#x20;such&#x20;as&#x20;-D&#x20;LAN_2_0&#x20;to&#x20;use&#x20;IPMI&#x20;ver&#x20;2.0&#x20;instead&#x20;of&#x20;1.5.&#x20;&#x20;These&#x20;options&#x20;will&#x20;also&#x20;be&#x20;passed&#x20;to&#x20;the&#x20;IPMI&#x20;plugin&#x20;when&#x20;the&#x20;current&#x20;values&#x20;are&#x20;read.\",\"value\":\"\",\"hide\":\"\"}}');
-INSERT INTO `trecon_script` VALUES (5,'WMI&#x20;Recon&#x20;Script','This&#x20;script&#x20;is&#x20;used&#x20;to&#x20;automatically&#x20;gather&#x20;host&#x20;information&#x20;via&#x20;WMI.&#x0d;&#x0a;Available&#x20;parameters:&#x0d;&#x0a;&#x0d;&#x0a;*&#x20;Network&#x20;=&#x20;network&#x20;to&#x20;scan&#x20;&#40;e.g.&#x20;192.168.100.0/24&#41;.&#x0d;&#x0a;*&#x20;WMI&#x20;auth&#x20;=&#x20;comma&#x20;separated&#x20;list&#x20;of&#x20;WMI&#x20;authentication&#x20;tokens&#x20;in&#x20;the&#x20;format&#x20;username%password&#x20;&#40;e.g.&#x20;Administrador%pass&#41;.&#x0d;&#x0a;&#x0d;&#x0a;See&#x20;the&#x20;documentation&#x20;for&#x20;more&#x20;information.','/usr/share/pandora_server/util/recon_scripts/wmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"WMI&#x20;auth\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"}}');
-INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Application.VMware', 'Discovery&#x20;Application&#x20;script&#x20;to&#x20;monitor&#x20;VMware&#x20;technologies&#x20;&#40;ESXi,&#x20;VCenter,&#x20;VSphere&#41;', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
-INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Cloud', 'Discovery&#x20;Cloud&#x20;script&#x20;to&#x20;monitor&#x20;Cloud&#x20;technologies&#x20;&#40;AWS.EC2,&#x20;AWS.S3,&#x20;AWS.RDS,&#x20RDS,&#x20AWS.EKS&#41;', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (0, 'IPMI&#x20;Recon','Specific&#x20;Pandora&#x20;FMS&#x20;Intel&#x20;DCM&#x20;Discovery&#x20;&#40;c&#41;&#x20;Artica&#x20;ST&#x20;2011&#x20;&lt;info@artica.es&gt;&#x0d;&#x0a;&#x0d;&#x0a;Usage:&#x20;./ipmi-recon.pl&#x20;&lt;task_id&gt;&#x20;&lt;group_id&gt;&#x20;&lt;create_incident_flag&gt;&#x20;&lt;custom_field1&gt;&#x20;&lt;custom_field2&gt;&#x20;&lt;custom_field3&gt;&#x20;&lt;custom_field4&gt;&#x0d;&#x0a;&#x0d;&#x0a;*&#x20;custom_field1&#x20;=&#x20;Network&#x20;i.e.:&#x20;192.168.100.0/24&#x0d;&#x0a;*&#x20;custom_field2&#x20;=&#x20;Username&#x0d;&#x0a;*&#x20;custom_field3&#x20;=&#x20;Password&#x0d;&#x0a;*&#x20;custom_field4&#x20;=&#x20;Additional&#x20;parameters&#x20;i.e.:&#x20;-D&#x20;LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.:&#x20;192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional&#x20;parameters\",\"help\":\"Optional&#x20;additional&#x20;parameters&#x20;such&#x20;as&#x20;-D&#x20;LAN_2_0&#x20;to&#x20;use&#x20;IPMI&#x20;ver&#x20;2.0&#x20;instead&#x20;of&#x20;1.5.&#x20;&#x20;These&#x20;options&#x20;will&#x20;also&#x20;be&#x20;passed&#x20;to&#x20;the&#x20;IPMI&#x20;plugin&#x20;when&#x20;the&#x20;current&#x20;values&#x20;are&#x20;read.\",\"value\":\"\",\"hide\":\"\"}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (1, 'Discovery.Application.VMware', 'Discovery&#x20;Application&#x20;script&#x20;to&#x20;monitor&#x20;VMware&#x20;technologies&#x20;&#40;ESXi,&#x20;VCenter,&#x20;VSphere&#41;', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (100,'Discovery.Cloud', 'Discovery&#x20;Cloud&#x20;script&#x20;to&#x20;monitor&#x20;Cloud&#x20;technologies&#x20;&#40;AWS.EC2,&#x20;AWS.S3,&#x20;AWS.RDS,&#x20RDS,&#x20AWS.EKS&#41;', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
 
 INSERT INTO `tplugin` (`id`, `name`, `description`, `max_timeout`, `execute`, `plugin_type`, `macros`, `parameters`) VALUES (1,'IPMI&#x20;Plugin','Plugin&#x20;to&#x20;get&#x20;IPMI&#x20;monitors&#x20;from&#x20;a&#x20;IPMI&#x20;Device.',0,'/usr/share/pandora_server/util/plugin/ipmi-plugin.pl',0,'{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Target&#x20;IP\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"true\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Sensor\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"5\":{\"macro\":\"_field5_\",\"desc\":\"Additional&#x20;Options\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"}}','-h&#x20;_field1_&#x20;-u&#x20;_field2_&#x20;-p&#x20;_field3_&#x20;-s&#x20;_field4_&#x20;--&#x20;_field5_');
 
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 393734bc85..5885e36611 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -194,6 +194,8 @@ sub new {
 	# Perform some sanity checks.
 	die("No subnet was specified.") unless defined($self->{'subnets'});
 
+	$self = bless($self, $class);
+
 	# Check SNMP params id SNMP is enabled
 	if ($self->{'snmp_enabled'}) {
 
@@ -240,7 +242,7 @@ sub new {
 			# Disable SNMP scans if no community was given.
 			if (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) {
 				$self->{'snmp_enabled'} = 0;
-				$self->call('message', "There is not any SNMP community configured.", 5);
+				$self->call('message', "There is no SNMP community configured.", 5);
 
 			}
 		}
@@ -270,7 +272,7 @@ sub new {
 		$self->{'snmp_security_level'} = '';
 	}
 
-	return bless($self, $class);
+	return $self;
 }
 
 ########################################################################################
@@ -1540,7 +1542,7 @@ sub snmp_get($$$) {
 		my %output_hash;
 		foreach my $vlan (@vlans) {
 			my $command = $self->snmp_get_command($device, $oid, $community, $vlan);
-			foreach my $line (`$vlan`) {
+			foreach my $line (`$command`) {
 				$output_hash{$line} = 1;
 			}
 		}

From 798a2aad162aa91459991ad87173ba827921015f Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 3 Apr 2019 18:13:19 +0200
Subject: [PATCH 04/31] WIP discovery F3

Former-commit-id: 19570468cf4de9f600ab9a01468d1e59c69e6939
---
 pandora_console/extras/mr/27.sql              | 11 ++-
 .../wizards/DiscoveryTaskList.class.php       | 43 ++++++---
 pandora_console/include/constants.php         |  8 +-
 pandora_console/include/styles/wizard.css     |  4 +-
 pandora_console/pandoradb.sql                 |  1 +
 pandora_console/pandoradb_data.sql            |  5 +-
 .../lib/PandoraFMS/DiscoveryServer.pm         | 94 +++++++++++++++++-
 .../lib/PandoraFMS/Recon/Applications         |  1 +
 pandora_server/lib/PandoraFMS/Recon/Base.pm   | 96 ++++++++++++++++++-
 pandora_server/lib/PandoraFMS/Recon/Cloud     |  1 +
 pandora_server/lib/PandoraFMS/Recon/Util.pm   | 80 +++++++++++-----
 11 files changed, 292 insertions(+), 52 deletions(-)
 create mode 120000 pandora_server/lib/PandoraFMS/Recon/Applications
 create mode 120000 pandora_server/lib/PandoraFMS/Recon/Cloud

diff --git a/pandora_console/extras/mr/27.sql b/pandora_console/extras/mr/27.sql
index 5dc8a47d2f..f419521005 100644
--- a/pandora_console/extras/mr/27.sql
+++ b/pandora_console/extras/mr/27.sql
@@ -1,11 +1,12 @@
 START TRANSACTION;
 
 ALTER TABLE `trecon_script` ADD COLUMN `type` int NOT NULL default 0;
+ALTER TABLE `trecon_task` ADD COLUMN `type` int NOT NULL default 0;
+
+UPDATE `trecon_script` SET `type` = 1 WHERE `name`="Discovery.Application.VMware";
+UPDATE `trecon_script` SET `type` = 2 WHERE `name`="Discovery.Cloud";
+UPDATE `trecon_script` SET `type` = 3 WHERE `name` LIKE "IPAM%Recon";
+UPDATE `trecon_script` SET `type` = 4 WHERE `name` LIKE "IPMI%Recon";
 
-UPDATE trecon_script SET `type` = 1 WHERE `name`="Discovery.Application.VMware";
-UPDATE trecon_script SET `type` = 2 WHERE `name`="Discovery.Application.MySQL";
-UPDATE trecon_script SET `type` = 3 WHERE `name`="Discovery.Application.Oracle";
-UPDATE trecon_script SET `type` = 100 WHERE `name`="Discovery.Cloud";
-UPDATE trecon_script SET `type` = 101 WHERE `name`="Discovery.Cloud.RDS";
 
 COMMIT;
\ No newline at end of file
diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 610353ebb7..00221aba1a 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -464,15 +464,30 @@ class DiscoveryTaskList extends Wizard
                 }
 
                 if ($task['id_recon_script'] == 0) {
-                    // Discovery NetScan.
-                    $data[6] = html_print_image(
-                        'images/network.png',
-                        true,
-                        ['title' => __('Discovery NetScan')]
-                    ).'&nbsp;&nbsp;';
-                    $data[6] .= network_profiles_get_name(
-                        $task['id_network_profile']
-                    );
+                    switch ($task['type']) {
+                        case DISCOVERY_APP_MYSQL:
+                            // Discovery Applications MySQL.
+                            $data[6] = html_print_image(
+                                'images/network.png',
+                                true,
+                                ['title' => __('Discovery Applications MySQL')]
+                            ).'&nbsp;&nbsp;';
+                            $data[6] .= __('Discovery.App.MySQL');
+                        break;
+
+                        case DISCOVERY_HOSTDEVICES:
+                        default:
+                            // Discovery NetScan.
+                            $data[6] = html_print_image(
+                                'images/network.png',
+                                true,
+                                ['title' => __('Discovery NetScan')]
+                            ).'&nbsp;&nbsp;';
+                            $data[6] .= network_profiles_get_name(
+                                $task['id_network_profile']
+                            );
+                        break;
+                    }
                 } else {
                     // APP recon task.
                     $data[6] = html_print_image(
@@ -612,12 +627,14 @@ class DiscoveryTaskList extends Wizard
      */
     public function getTargetWiz($task)
     {
-        // TODO: Do not use description. Use recon_script ID instead.
-        switch ($task['description']) {
-            case 'Discovery.Application.VMware':
+        switch ($task['type']) {
+            case DISCOVERY_APP_MYSQL:
+            return 'wiz=app&mode=mysql&page=0';
+
+            case DISCOVERY_APP_VMWARE:
             return 'wiz=app&mode=vmware&page=0';
 
-            case CLOUDWIZARD_AWS_DESCRIPTION:
+            case DISCOVERY_CLOUD_AWS:
             return 'wiz=cloud&mode=amazonws&page=1';
 
             case 'console_task':
diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php
index ceb48d1d0f..7266e9eff4 100644
--- a/pandora_console/include/constants.php
+++ b/pandora_console/include/constants.php
@@ -595,12 +595,10 @@ define('DISCOVERY_CLOUD_AWS_RDS', 7);
 define('DISCOVERY_SCRIPT_HOSTDEVICES_CUSTOM', 0);
 // Standard applications.
 define('DISCOVERY_SCRIPT_APP_VMWARE', 1);
-define('DISCOVERY_SCRIPT_APP_MYSQL', 2);
-define('DISCOVERY_SCRIPT_APP_ORACLE', 3);
 // Cloud environments.
-define('DISCOVERY_SCRIPT_CLOUD_AWS', 100);
-define('DISCOVERY_SCRIPT_CLOUD_AWS_EC2', 101);
-define('DISCOVERY_SCRIPT_CLOUD_AWS_RDS', 102);
+define('DISCOVERY_SCRIPT_CLOUD_AWS', 2);
+define('DISCOVERY_SCRIPT_IPAM_RECON', 3);
+define('DISCOVERY_SCRIPT_IPMI_RECON', 4);
 
 // Discovery task descriptions.
 define('CLOUDWIZARD_AWS_DESCRIPTION', 'Discovery.Cloud.AWS.EC2');
diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css
index 869ea85f2c..d7ec2e4ee5 100644
--- a/pandora_console/include/styles/wizard.css
+++ b/pandora_console/include/styles/wizard.css
@@ -16,8 +16,10 @@ ul.wizard li > label:not(.p-switch) {
 }
 
 ul.wizard li > textarea {
-  width: 250px;
+  width: 600px;
+  height: 15em;
   display: inline-block;
+  font-family: monospace;
 }
 
 .hidden {
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index d7c87538af..f3677663b4 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -786,6 +786,7 @@ CREATE TABLE IF NOT EXISTS `trecon_task` (
 	`auth_strings` text,
 	`autoconfiguration_enabled` tinyint(1) unsigned default '0',
 	`summary` text,
+	`type` int NOT NULL default 0,
 	PRIMARY KEY  (`id_rt`),
 	KEY `recon_task_daemon` (`id_recon_server`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql
index 4e30bdef7e..b8cc4be8b1 100644
--- a/pandora_console/pandoradb_data.sql
+++ b/pandora_console/pandoradb_data.sql
@@ -1135,9 +1135,10 @@ INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (3, 'Monitoring&#x
 INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (4, 'Group&#x20;view', 'select&#x20;t1.nombre,&#x20;&#40;select&#x20;count&#40;t3.id_agente&#41;&#x20;from&#x20;tagente&#x20;as&#x20;t3&#x20;where&#x20;t1.id_grupo&#x20;=&#x20;t3.id_grupo&#41;&#x20;as&#x20;agents,&#x20;&#40;SELECT&#x20;COUNT&#40;t4.id_agente&#41;&#x20;FROM&#x20;tagente&#x20;as&#x20;t4&#x20;WHERE&#x20;t4.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;t4.disabled&#x20;=&#x20;0&#x20;AND&#x20;t4.ultimo_contacto&#x20;&lt;&#x20;NOW&#40;&#41;&#x20;-&#x20;&#40;intervalo&#x20;/&#x20;&#40;1/2&#41;&#41;&#41;&#x20;as&#x20;agent_unknown,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.id_agente&#x20;=&#x20;tagente_estado.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;utimestamp&#x20;&gt;&#x20;0&#x20;AND&#x20;tagente_modulo.id_tipo_modulo&#x20;NOT&#x20;IN&#40;21,22,23,24,100&#41;&#x20;AND&#x20;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&gt;=&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#41;&#x20;as&#x20;monitor_unknow,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.id_agente&#x20;=&#x20;tagente_estado.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_modulo.id_tipo_modulo&#x20;NOT&#x20;IN&#x20;&#40;21,22,23,24&#41;&#x20;AND&#x20;utimestamp&#x20;=&#x20;0&#41;&#x20;as&#x20;monitor_no_init,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_estado.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;estado&#x20;=&#x20;0&#x20;AND&#x20;&#40;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&lt;&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24,100&#41;&#41;&#41;&#x20;AND&#x20;&#40;utimestamp&#x20;&gt;&#x20;0&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24&#41;&#41;&#41;&#41;&#x20;as&#x20;monitor_ok,&#x20;&#40;SELECT&#x20;COUNT&#40;tagente_estado.id_agente_estado&#41;&#x20;FROM&#x20;tagente_estado,&#x20;tagente,&#x20;tagente_modulo&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente_estado.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;estado&#x20;=&#x20;1&#x20;AND&#x20;&#40;&#40;UNIX_TIMESTAMP&#40;NOW&#40;&#41;&#41;&#x20;-&#x20;tagente_estado.utimestamp&#41;&#x20;&lt;&#x20;&#40;tagente_estado.current_interval&#x20;/&#x20;&#40;1/2&#41;&#41;&#x20;OR&#x20;&#40;tagente_modulo.id_tipo_modulo&#x20;IN&#40;21,22,23,24,100&#41;&#41;&#41;&#x20;AND&#x20;utimestamp&#x20;&gt;&#x20;0&#41;&#x20;as&#x20;monitor_critical,&#x20;&#40;SELECT&#x20;COUNT&#40;talert_template_modules.id&#41;&#x20;FROM&#x20;talert_template_modules,&#x20;tagente_modulo,&#x20;tagente_estado,&#x20;tagente&#x20;WHERE&#x20;tagente.id_grupo&#x20;=&#x20;t1.id_grupo&#x20;AND&#x20;tagente_modulo.id_agente&#x20;=&#x20;tagente.id_agente&#x20;AND&#x20;tagente_estado.id_agente_modulo&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;tagente_modulo.disabled&#x20;=&#x20;0&#x20;AND&#x20;tagente.disabled&#x20;=&#x20;0&#x20;AND&#x20;talert_template_modules.id_agent_module&#x20;=&#x20;tagente_modulo.id_agente_modulo&#x20;AND&#x20;times_fired&#x20;&gt;&#x20;0&#41;&#x20;as&#x20;monitor_alert_fired&#x20;from&#x20;tgrupo&#x20;as&#x20;t1&#x20;where&#x20;0&#x20;&lt;&#x20;&#40;select&#x20;count&#40;t2.id_agente&#41;&#x20;from&#x20;tagente&#x20;as&#x20;t2&#x20;where&#x20;t1.id_grupo&#x20;=&#x20;t2.id_grupo&#41;');
 
 -- trecon scripts
-INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (0, 'IPMI&#x20;Recon','Specific&#x20;Pandora&#x20;FMS&#x20;Intel&#x20;DCM&#x20;Discovery&#x20;&#40;c&#41;&#x20;Artica&#x20;ST&#x20;2011&#x20;&lt;info@artica.es&gt;&#x0d;&#x0a;&#x0d;&#x0a;Usage:&#x20;./ipmi-recon.pl&#x20;&lt;task_id&gt;&#x20;&lt;group_id&gt;&#x20;&lt;create_incident_flag&gt;&#x20;&lt;custom_field1&gt;&#x20;&lt;custom_field2&gt;&#x20;&lt;custom_field3&gt;&#x20;&lt;custom_field4&gt;&#x0d;&#x0a;&#x0d;&#x0a;*&#x20;custom_field1&#x20;=&#x20;Network&#x20;i.e.:&#x20;192.168.100.0/24&#x0d;&#x0a;*&#x20;custom_field2&#x20;=&#x20;Username&#x0d;&#x0a;*&#x20;custom_field3&#x20;=&#x20;Password&#x0d;&#x0a;*&#x20;custom_field4&#x20;=&#x20;Additional&#x20;parameters&#x20;i.e.:&#x20;-D&#x20;LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.:&#x20;192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional&#x20;parameters\",\"help\":\"Optional&#x20;additional&#x20;parameters&#x20;such&#x20;as&#x20;-D&#x20;LAN_2_0&#x20;to&#x20;use&#x20;IPMI&#x20;ver&#x20;2.0&#x20;instead&#x20;of&#x20;1.5.&#x20;&#x20;These&#x20;options&#x20;will&#x20;also&#x20;be&#x20;passed&#x20;to&#x20;the&#x20;IPMI&#x20;plugin&#x20;when&#x20;the&#x20;current&#x20;values&#x20;are&#x20;read.\",\"value\":\"\",\"hide\":\"\"}}');
 INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (1, 'Discovery.Application.VMware', 'Discovery&#x20;Application&#x20;script&#x20;to&#x20;monitor&#x20;VMware&#x20;technologies&#x20;&#40;ESXi,&#x20;VCenter,&#x20;VSphere&#41;', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
-INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (100,'Discovery.Cloud', 'Discovery&#x20;Cloud&#x20;script&#x20;to&#x20;monitor&#x20;Cloud&#x20;technologies&#x20;&#40;AWS.EC2,&#x20;AWS.S3,&#x20;AWS.RDS,&#x20RDS,&#x20AWS.EKS&#41;', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (2, 'Discovery.Cloud', 'Discovery&#x20;Cloud&#x20;script&#x20;to&#x20;monitor&#x20;Cloud&#x20;technologies&#x20;&#40;AWS.EC2,&#x20;AWS.S3,&#x20;AWS.RDS,&#x20RDS,&#x20AWS.EKS&#41;', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration&#x20;file","help":"","value":"","hide":""}}');
+-- IPAM is 3.
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (4, 'IPMI&#x20;Recon','Specific&#x20;Pandora&#x20;FMS&#x20;Intel&#x20;DCM&#x20;Discovery&#x20;&#40;c&#41;&#x20;Artica&#x20;ST&#x20;2011&#x20;&lt;info@artica.es&gt;&#x0d;&#x0a;&#x0d;&#x0a;Usage:&#x20;./ipmi-recon.pl&#x20;&lt;task_id&gt;&#x20;&lt;group_id&gt;&#x20;&lt;create_incident_flag&gt;&#x20;&lt;custom_field1&gt;&#x20;&lt;custom_field2&gt;&#x20;&lt;custom_field3&gt;&#x20;&lt;custom_field4&gt;&#x0d;&#x0a;&#x0d;&#x0a;*&#x20;custom_field1&#x20;=&#x20;Network&#x20;i.e.:&#x20;192.168.100.0/24&#x0d;&#x0a;*&#x20;custom_field2&#x20;=&#x20;Username&#x0d;&#x0a;*&#x20;custom_field3&#x20;=&#x20;Password&#x0d;&#x0a;*&#x20;custom_field4&#x20;=&#x20;Additional&#x20;parameters&#x20;i.e.:&#x20;-D&#x20;LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.:&#x20;192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional&#x20;parameters\",\"help\":\"Optional&#x20;additional&#x20;parameters&#x20;such&#x20;as&#x20;-D&#x20;LAN_2_0&#x20;to&#x20;use&#x20;IPMI&#x20;ver&#x20;2.0&#x20;instead&#x20;of&#x20;1.5.&#x20;&#x20;These&#x20;options&#x20;will&#x20;also&#x20;be&#x20;passed&#x20;to&#x20;the&#x20;IPMI&#x20;plugin&#x20;when&#x20;the&#x20;current&#x20;values&#x20;are&#x20;read.\",\"value\":\"\",\"hide\":\"\"}}');
 
 INSERT INTO `tplugin` (`id`, `name`, `description`, `max_timeout`, `execute`, `plugin_type`, `macros`, `parameters`) VALUES (1,'IPMI&#x20;Plugin','Plugin&#x20;to&#x20;get&#x20;IPMI&#x20;monitors&#x20;from&#x20;a&#x20;IPMI&#x20;Device.',0,'/usr/share/pandora_server/util/plugin/ipmi-plugin.pl',0,'{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Target&#x20;IP\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"true\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Sensor\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"5\":{\"macro\":\"_field5_\",\"desc\":\"Additional&#x20;Options\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"}}','-h&#x20;_field1_&#x20;-u&#x20;_field2_&#x20;-p&#x20;_field3_&#x20;-s&#x20;_field4_&#x20;--&#x20;_field5_');
 
diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 918f0bcc4a..70abab5d2a 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -150,6 +150,9 @@ sub data_consumer ($$) {
 	my ($self, $task_id) = @_;
 	my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
 
+	# Get server id.
+	my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType());
+
 	# Get recon task data	
 	my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id);	
 	return -1 unless defined ($task);
@@ -201,7 +204,9 @@ sub data_consumer ($$) {
 			auth_strings_array => \@auth_strings,
 			autoconfiguration_enabled => $task->{'autoconfiguration_enabled'},
 			main_event_id => $main_event,
-			%{$pa_config}
+			server_id => $server_id,
+			%{$pa_config},
+			task_data => $task
 		);
 
 		$recon->scan();
@@ -413,6 +418,93 @@ sub PandoraFMS::Recon::Base::connect_agents($$$$$) {
 	}
 }
 
+
+##########################################################################
+# Create agents from db_scan.
+# data = [
+#	'agent_data' => {},
+#	'module_data' => []
+# ]
+##########################################################################
+sub PandoraFMS::Recon::Base::create_agents($$) {
+	my ($self, $data) = @_;
+
+	my $pa_config = $self->{'pa_config'};
+	my $dbh = $self->{'dbh'};
+	my $server_id = $self->{'server_id'};
+
+	return undef if (ref($data) ne "ARRAY");
+
+	foreach my $information (@{$data}) {
+		my $agent = $information->{'agent_data'};
+		my $modules = $information->{'module_data'};
+		my $force_processing = 0;
+
+		# Search agent
+		my $current_agent = PandoraFMS::Core::locate_agent(
+			$pa_config, $dbh, $agent->{'agent_name'}
+		);
+
+		my $parent_id;
+		if (defined($agent->{'parent_agent'})) {
+			$parent_id = PandoraFMS::Core::locate_agent(
+				$pa_config, $dbh, $agent->{'parent_agent'}
+			);
+		}
+
+		my $agent_id;
+
+		if (!$current_agent) {
+			# Create agent.
+			$agent_id = pandora_create_agent(
+				$pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
+				$agent->{'address'}, $agent->{'id_group'}, $parent_id,
+				$agent->{'os'}, $agent->{'description'}, $agent->{'interval'},
+				$dbh, $agent->{'timezone_offset'}
+			);
+
+			$current_agent = $parent_id = PandoraFMS::Core::locate_agent(
+				$pa_config, $dbh, $agent->{'agent_name'}
+			);
+
+			$force_processing = 1;
+
+		} else {
+			$agent_id = $current_agent->{'id_agente'};
+		}
+
+		if (!defined($agent_id)) {
+			return undef;
+		}
+
+		if ($agent->{'address'} ne '') {
+			pandora_add_agent_address(
+				$pa_config, $agent_id, $agent->{'agent_name'},
+				$agent->{'address'}, $dbh
+			);
+		}
+
+		# Update agent information
+		pandora_update_agent(
+			$pa_config, time(), $agent_id,
+			$agent->{'os_version'}, $agent->{'agent_version'},
+			$agent->{'interval'}, $dbh, undef, $parent_id
+		);
+
+		# Add modules.
+		if (ref($modules) eq "ARRAY") {
+			foreach my $module (@{$modules}) {
+				pandora_process_module(
+					$pa_config, {'data' => $module->{'value'}}, $current_agent, $module,
+					$module->{'type'}, '', time(), $server_id, $dbh
+				);
+			}
+		}
+	}
+
+}
+
+
 ##########################################################################
 # Create an agent for the given device. Returns the ID of the new (or
 # existing) agent, undef on error.
diff --git a/pandora_server/lib/PandoraFMS/Recon/Applications b/pandora_server/lib/PandoraFMS/Recon/Applications
new file mode 120000
index 0000000000..f584395db5
--- /dev/null
+++ b/pandora_server/lib/PandoraFMS/Recon/Applications
@@ -0,0 +1 @@
+/tmp/pandora_enterprise/pandora_server/PandoraFMS-Enterprise/lib/PandoraFMS/Recon/Applications
\ No newline at end of file
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 5885e36611..9612599aa7 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -20,7 +20,16 @@ use constant {
 	STEP_SCANNING => 1,
 	STEP_AFT => 2,
 	STEP_TRACEROUTE => 3,
-	STEP_GATEWAY => 4
+	STEP_GATEWAY => 4,
+	STEP_STATISTICS => 1,
+	STEP_DATABASE_SCAN => 2,
+	STEP_CUSTOM_QUERIES => 3,
+	DISCOVERY_HOSTDEVICES => 0,
+	DISCOVERY_HOSTDEVICES_CUSTOM => 1,
+	DISCOVERY_CLOUD_AWS => 2,
+	DISCOVERY_APP_VMWARE => 3,
+	DISCOVERY_APP_MYSQL => 4,
+	DISCOVERY_APP_ORACLE => 5
 };
 
 # /dev/null
@@ -1417,6 +1426,83 @@ sub scan_subnet($) {
 	}
 }
 
+##########################################################################
+# Perform a DB scan.
+##########################################################################
+sub db_scan($) {
+	my ($self) = @_;
+	my ($progress, $step);
+
+	my $type = '';
+
+	if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) {
+		$type = 'MySQL';
+	} elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) {
+		$type = 'Oracle';
+	} else {
+		# Unrecognized task type.
+		call('message', 'Unrecognized task type', 1);
+		$self->call('update_progress', -1);
+		return;
+	}
+
+	# Connect to target.
+	my $dbObj = PandoraFMS::Recon::Util::enterprise_new(
+		'PandoraFMS::Recon::Applications::'.$type,
+		$self->{'task_data'}
+	);
+
+	if (!defined($dbObj)) {
+		call('message', 'Cannot connect to target ' .'', 3);
+		$self->call('update_progress', -1);
+		return;
+	}
+
+	my @modules;
+
+	# Analyze.
+	$self->{'step'} = STEP_STATISTICS;
+	$self->{'c_network_name'} = $dbObj->get_host();
+	$self->call('update_progress', 10);
+
+	# Retrieve connection statistics.
+	# Retrieve uptime statistics
+	# Retrieve query stats
+	# Retrieve connections
+	# Retrieve innodb
+	# Retrieve cache
+	push @modules, $dbObj->get_statistics();
+	$self->call('update_progress', 50);
+
+
+	# Custom queries.
+	push @modules, $dbObj->execute_custom_queries();
+	$self->call('update_progress', 90);
+
+	my $data = [
+		{
+			'agent_data' => {
+				'agent_name' => $dbObj->get_agent_name(),
+				'os' => $type,
+				'os_version' => 'Discovery',
+				'interval' => $self->{'task_data'}->{'interval_sweep'},
+				'id_group' => $self->{'task_data'}->{'id_group'},
+				'address' => $dbObj->get_host(),
+
+			},
+			'module_data' => \@modules,
+		}
+	];
+
+	$self->call('create_agents', $data);
+
+	# Update progress.
+	# Done!
+	$self->{'step'} = '';
+	$self->call('update_progress', -1);
+
+}
+
 ##########################################################################
 # Perform a network scan.
 ##########################################################################
@@ -1427,6 +1513,14 @@ sub scan($) {
 	# 1%
 	$self->call('update_progress', 1);
 
+	if (defined($self->{'task_data'})) {
+		if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL
+		||  $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) {
+			# Database scan.
+			return $self->db_scan();
+		}
+	}
+
 	# Find devices.
 	$self->call('message', "[1/5] Scanning the network...", 3);
 	$self->{'step'} = STEP_SCANNING;
diff --git a/pandora_server/lib/PandoraFMS/Recon/Cloud b/pandora_server/lib/PandoraFMS/Recon/Cloud
new file mode 120000
index 0000000000..1980c9db6a
--- /dev/null
+++ b/pandora_server/lib/PandoraFMS/Recon/Cloud
@@ -0,0 +1 @@
+/tmp/pandora_enterprise/pandora_server/PandoraFMS-Enterprise/lib/PandoraFMS/Recon/Cloud
\ No newline at end of file
diff --git a/pandora_server/lib/PandoraFMS/Recon/Util.pm b/pandora_server/lib/PandoraFMS/Recon/Util.pm
index 85d251ff1b..64cc7b28e6 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Util.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Util.pm
@@ -12,16 +12,47 @@ use lib '/usr/lib/perl5';
 use Socket qw/inet_aton/;
 
 our @ISA = ("Exporter");
-our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
+our %EXPORT_TAGS = ( 'all' => [qw( )] );
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
 our @EXPORT = qw(
-	ip_to_long
-	mac_matches
-	mac_to_dec
-	parse_mac
-	subnet_matches
+  enterprise_new
+  ip_to_long
+  mac_matches
+  mac_to_dec
+  parse_mac
+  subnet_matches
 );
 
+########################################################################################
+# Return an Enterprise Recon object.
+########################################################################################
+sub enterprise_new($$) {
+	my ($class, $arguments) = @_;
+
+	my @args;
+	if (ref($arguments) eq "HASH") {
+		@args = %{$arguments};
+	}
+	if (ref($arguments) eq "ARRAY") {
+		@args = @{$arguments};
+	}
+
+	# Try to load the module
+	if ($^O eq 'MSWin32') {
+		# If the Windows service dies the service is stopped, even inside an eval ($RUN is set to 0)!
+		eval 'local $SIG{__DIE__}; require '.$class.';';
+	}else {
+		eval 'require '.$class.';';
+	}
+	if ($@) {
+		# Not loaded.
+		return undef;
+	}
+
+	return new $class(@args);
+}
+
+
 ########################################################################################
 # Return the numeric representation of the given IP address.
 ########################################################################################
@@ -35,13 +66,13 @@ sub ip_to_long($) {
 # Returns 1 if the two given MAC addresses are the same.
 ########################################################################################
 sub mac_matches($$) {
-    my ($mac_1, $mac_2) = @_;
+	my ($mac_1, $mac_2) = @_;
 
-    if (parse_mac($mac_1) eq parse_mac($mac_2)) {
-        return 1;
-    }
+	if (parse_mac($mac_1) eq parse_mac($mac_2)) {
+		return 1;
+	}
 
-    return 0;
+	return 0;
 }
 
 ########################################################################################
@@ -53,7 +84,7 @@ sub mac_to_dec($) {
 	my $dec_mac = '';
 	my @elements = split(/:/, $mac);
 	foreach my $element (@elements) {
-        $dec_mac .= unpack('s', pack 's', hex($element)) .  '.'
+		$dec_mac .= unpack('s', pack 's', hex($element)) .  '.';
 	}
 	chop($dec_mac);
 
@@ -64,23 +95,23 @@ sub mac_to_dec($) {
 # Make sure all MAC addresses are in the same format (00 11 22 33 44 55 66).
 ########################################################################################
 sub parse_mac($) {
-    my ($mac) = @_;
+	my ($mac) = @_;
 
-    # Remove leading and trailing whitespaces.
-    $mac =~ s/(^\s+)|(\s+$)//g;
+	# Remove leading and trailing whitespaces.
+	$mac =~ s/(^\s+)|(\s+$)//g;
 
-    # Replace whitespaces and dots with colons.
-    $mac =~ s/\s+|\./:/g;
+	# Replace whitespaces and dots with colons.
+	$mac =~ s/\s+|\./:/g;
 
-    # Convert hex digits to uppercase.
-    $mac =~ s/([a-f])/\U$1/g;
+	# Convert hex digits to uppercase.
+	$mac =~ s/([a-f])/\U$1/g;
 
-    # Add a leading 0 to single digits.
-    $mac =~ s/^([0-9A-F]):/0$1:/g;
-    $mac =~ s/:([0-9A-F]):/:0$1:/g;
-    $mac =~ s/:([0-9A-F])$/:0$1/g;
+	# Add a leading 0 to single digits.
+	$mac =~ s/^([0-9A-F]):/0$1:/g;
+	$mac =~ s/:([0-9A-F]):/:0$1:/g;
+	$mac =~ s/:([0-9A-F])$/:0$1/g;
 
-    return $mac;
+	return $mac;
 }
 
 ########################################################################################
@@ -95,6 +126,7 @@ sub subnet_matches($$;$) {
 		$netaddr = $subnet;
 		$netmask = ip_to_long($mask);
 	}
+
 	# CIDR notation.
 	else {
 		($netaddr, $netmask) = split('/', $subnet);

From 60f37eac57c2e0063731adcac40f8af2236b2a45 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 3 Apr 2019 21:08:52 +0200
Subject: [PATCH 05/31] removed unused folders

Former-commit-id: 4c1870e836e7f05dd5a312e41c4f1f86bff26e22
---
 pandora_server/lib/PandoraFMS/Recon/Applications | 1 -
 pandora_server/lib/PandoraFMS/Recon/Cloud        | 1 -
 2 files changed, 2 deletions(-)
 delete mode 120000 pandora_server/lib/PandoraFMS/Recon/Applications
 delete mode 120000 pandora_server/lib/PandoraFMS/Recon/Cloud

diff --git a/pandora_server/lib/PandoraFMS/Recon/Applications b/pandora_server/lib/PandoraFMS/Recon/Applications
deleted file mode 120000
index f584395db5..0000000000
--- a/pandora_server/lib/PandoraFMS/Recon/Applications
+++ /dev/null
@@ -1 +0,0 @@
-/tmp/pandora_enterprise/pandora_server/PandoraFMS-Enterprise/lib/PandoraFMS/Recon/Applications
\ No newline at end of file
diff --git a/pandora_server/lib/PandoraFMS/Recon/Cloud b/pandora_server/lib/PandoraFMS/Recon/Cloud
deleted file mode 120000
index 1980c9db6a..0000000000
--- a/pandora_server/lib/PandoraFMS/Recon/Cloud
+++ /dev/null
@@ -1 +0,0 @@
-/tmp/pandora_enterprise/pandora_server/PandoraFMS-Enterprise/lib/PandoraFMS/Recon/Cloud
\ No newline at end of file

From 74303168ac9cfedebdaa209b5eeffaf37af555af Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 3 Apr 2019 21:55:11 +0200
Subject: [PATCH 06/31] WIP discovery F3

Former-commit-id: 493d05714a31c2f91f7b8ea5445397ebf1c526d7
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 13 ++++++++++---
 pandora_server/lib/PandoraFMS/Recon/Base.pm      |  2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 70abab5d2a..797190a259 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -494,9 +494,16 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 		# Add modules.
 		if (ref($modules) eq "ARRAY") {
 			foreach my $module (@{$modules}) {
-				pandora_process_module(
-					$pa_config, {'data' => $module->{'value'}}, $current_agent, $module,
-					$module->{'type'}, '', time(), $server_id, $dbh
+				my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module};
+
+				# Translate fields.
+				PandoraFMS::DataServer::process_module_data (
+					$pa_config, \%data_translated,
+					$server_id, $current_agent,
+					$module->{'name'}, $module->{'type'},
+					$agent->{'interval'},
+					strftime ("%Y/%m/%d %H:%M:%S", localtime()),
+					$dbh, $force_processing
 				);
 			}
 		}
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 9612599aa7..39c3bf0ba2 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1488,7 +1488,7 @@ sub db_scan($) {
 				'interval' => $self->{'task_data'}->{'interval_sweep'},
 				'id_group' => $self->{'task_data'}->{'id_group'},
 				'address' => $dbObj->get_host(),
-
+				'description' => '',
 			},
 			'module_data' => \@modules,
 		}

From 654e0c28f6c64eb0a34bf7b8f7d56fdaae9ef5b8 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 3 Apr 2019 22:44:06 +0200
Subject: [PATCH 07/31] WIP discovery F3 app db my multiserver

Former-commit-id: a85c048a6d4e755b76a7e042e04cfebdfe69b6f4
---
 pandora_server/lib/PandoraFMS/Recon/Base.pm | 101 +++++++++++---------
 1 file changed, 58 insertions(+), 43 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 39c3bf0ba2..d7fa83b6fb 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1446,55 +1446,70 @@ sub db_scan($) {
 		return;
 	}
 
-	# Connect to target.
-	my $dbObj = PandoraFMS::Recon::Util::enterprise_new(
-		'PandoraFMS::Recon::Applications::'.$type,
-		$self->{'task_data'}
-	);
+	my @targets = split /,/, $self->{'task_data'}->{'subnet'};
 
-	if (!defined($dbObj)) {
-		call('message', 'Cannot connect to target ' .'', 3);
-		$self->call('update_progress', -1);
-		return;
-	}
+	my $i = 0;
+	foreach my $target (@targets) {
+		call('message', 'Checking target ' . $target, 10);
 
-	my @modules;
+		# Force target acquirement.
+		$self->{'task_data'}->{'dbhost'} = $target;
+		$self->{'task_data'}->{'target_index'} = $i++;
 
-	# Analyze.
-	$self->{'step'} = STEP_STATISTICS;
-	$self->{'c_network_name'} = $dbObj->get_host();
-	$self->call('update_progress', 10);
+		# Connect to target.
+		my $dbObj = PandoraFMS::Recon::Util::enterprise_new(
+			'PandoraFMS::Recon::Applications::'.$type,
+			$self->{'task_data'}
+		);
 
-	# Retrieve connection statistics.
-	# Retrieve uptime statistics
-	# Retrieve query stats
-	# Retrieve connections
-	# Retrieve innodb
-	# Retrieve cache
-	push @modules, $dbObj->get_statistics();
-	$self->call('update_progress', 50);
-
-
-	# Custom queries.
-	push @modules, $dbObj->execute_custom_queries();
-	$self->call('update_progress', 90);
-
-	my $data = [
-		{
-			'agent_data' => {
-				'agent_name' => $dbObj->get_agent_name(),
-				'os' => $type,
-				'os_version' => 'Discovery',
-				'interval' => $self->{'task_data'}->{'interval_sweep'},
-				'id_group' => $self->{'task_data'}->{'id_group'},
-				'address' => $dbObj->get_host(),
-				'description' => '',
-			},
-			'module_data' => \@modules,
+		if (!defined($dbObj)) {
+			call('message', 'Cannot connect to target ' . $target, 3);
+			next;
 		}
-	];
 
-	$self->call('create_agents', $data);
+		my @modules;
+
+		# Analyze.
+		$self->{'step'} = STEP_STATISTICS;
+		$self->{'c_network_name'} = $dbObj->get_host();
+		$self->call('update_progress', 10);
+
+		# Retrieve connection statistics.
+		# Retrieve uptime statistics
+		# Retrieve query stats
+		# Retrieve connections
+		# Retrieve innodb
+		# Retrieve cache
+		push @modules, $dbObj->get_statistics();
+		$self->call('update_progress', 50);
+
+
+		# Custom queries.
+		push @modules, $dbObj->execute_custom_queries();
+		$self->call('update_progress', 90);
+
+		my $data = [
+			{
+				'agent_data' => {
+					'agent_name' => $dbObj->get_agent_name(),
+					'os' => $type,
+					'os_version' => 'Discovery',
+					'interval' => $self->{'task_data'}->{'interval_sweep'},
+					'id_group' => $self->{'task_data'}->{'id_group'},
+					'address' => $dbObj->get_host(),
+					'description' => '',
+				},
+				'module_data' => \@modules,
+			}
+		];
+
+		use Data::Dumper;
+		print Dumper($data);
+		$self->call('create_agents', $data);
+
+		# Destroy item.
+		undef($dbObj);
+	}
 
 	# Update progress.
 	# Done!

From 9e83f139e15e7f8b44bd92363cb5d6b405f66302 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 3 Apr 2019 22:52:37 +0200
Subject: [PATCH 08/31] WIP discovery f3

Former-commit-id: cee7ee096e0a0c065bc4312a149ee223303224fc
---
 pandora_server/lib/PandoraFMS/Recon/Base.pm | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index d7fa83b6fb..fb9967a54d 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1464,8 +1464,11 @@ sub db_scan($) {
 
 		if (!defined($dbObj)) {
 			call('message', 'Cannot connect to target ' . $target, 3);
+			$self->{'summary'}->{'not_alive'} += 1;
 			next;
 		}
+		$self->{'summary'}->{'discovered'} += 1;
+		$self->{'summary'}->{'alive'} += 1;
 
 		my @modules;
 
@@ -1503,8 +1506,6 @@ sub db_scan($) {
 			}
 		];
 
-		use Data::Dumper;
-		print Dumper($data);
 		$self->call('create_agents', $data);
 
 		# Destroy item.

From fcafe76943bc47112d58c532bbea8963470719f9 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 12:28:17 +0200
Subject: [PATCH 09/31] wip discovery f34

Former-commit-id: bb08450d3304ff140c4bae37e77b20a2329c600b
---
 .../lib/PandoraFMS/DiscoveryServer.pm         |  5 +-
 pandora_server/lib/PandoraFMS/Recon/Base.pm   | 93 +++++++++++--------
 2 files changed, 56 insertions(+), 42 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 797190a259..c97a393422 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -420,7 +420,7 @@ sub PandoraFMS::Recon::Base::connect_agents($$$$$) {
 
 
 ##########################################################################
-# Create agents from db_scan.
+# Create agents from db_scan. Uses DataServer methods.
 # data = [
 #	'agent_data' => {},
 #	'module_data' => []
@@ -494,9 +494,10 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 		# Add modules.
 		if (ref($modules) eq "ARRAY") {
 			foreach my $module (@{$modules}) {
+				# Translate data structure to simulate XML parser return.
 				my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module};
 
-				# Translate fields.
+				# Process modules.
 				PandoraFMS::DataServer::process_module_data (
 					$pa_config, \%data_translated,
 					$server_id, $current_agent,
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index fb9967a54d..2b04dab950 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1450,6 +1450,8 @@ sub db_scan($) {
 
 	my $i = 0;
 	foreach my $target (@targets) {
+		my @data;
+		my @modules;
 		call('message', 'Checking target ' . $target, 10);
 
 		# Force target acquirement.
@@ -1462,51 +1464,62 @@ sub db_scan($) {
 			$self->{'task_data'}
 		);
 
-		if (!defined($dbObj)) {
+		if (!$dbObj->is_connected()) {
 			call('message', 'Cannot connect to target ' . $target, 3);
 			$self->{'summary'}->{'not_alive'} += 1;
-			next;
+			push @modules, {
+				name => 'mysql_connection',
+				type => 'generic_proc',
+				data => 0,
+				description => 'MySQL availability'
+			};
+
+		} else {
+			$self->{'summary'}->{'discovered'} += 1;
+			$self->{'summary'}->{'alive'} += 1;
+
+			push @modules, {
+				name => 'mysql_connection',
+				type => 'generic_proc',
+				data => 1,
+				description => 'MySQL availability'
+			};
+
+			# Analyze.
+			$self->{'step'} = STEP_STATISTICS;
+			$self->{'c_network_name'} = $dbObj->get_host();
+			$self->call('update_progress', 10);
+
+			# Retrieve connection statistics.
+			# Retrieve uptime statistics
+			# Retrieve query stats
+			# Retrieve connections
+			# Retrieve innodb
+			# Retrieve cache
+			push @modules, $dbObj->get_statistics();
+			$self->call('update_progress', 50);
+
+
+			# Custom queries.
+			push @modules, $dbObj->execute_custom_queries();
+			$self->call('update_progress', 90);
 		}
-		$self->{'summary'}->{'discovered'} += 1;
-		$self->{'summary'}->{'alive'} += 1;
 
-		my @modules;
+		# Put engine agent at the beginning of the list.
+		unshift @data,{
+			'agent_data' => {
+				'agent_name' => $dbObj->get_agent_name(),
+				'os' => $type,
+				'os_version' => 'Discovery',
+				'interval' => $self->{'task_data'}->{'interval_sweep'},
+				'id_group' => $self->{'task_data'}->{'id_group'},
+				'address' => $dbObj->get_host(),
+				'description' => '',
+			},
+			'module_data' => \@modules,
+		};
 
-		# Analyze.
-		$self->{'step'} = STEP_STATISTICS;
-		$self->{'c_network_name'} = $dbObj->get_host();
-		$self->call('update_progress', 10);
-
-		# Retrieve connection statistics.
-		# Retrieve uptime statistics
-		# Retrieve query stats
-		# Retrieve connections
-		# Retrieve innodb
-		# Retrieve cache
-		push @modules, $dbObj->get_statistics();
-		$self->call('update_progress', 50);
-
-
-		# Custom queries.
-		push @modules, $dbObj->execute_custom_queries();
-		$self->call('update_progress', 90);
-
-		my $data = [
-			{
-				'agent_data' => {
-					'agent_name' => $dbObj->get_agent_name(),
-					'os' => $type,
-					'os_version' => 'Discovery',
-					'interval' => $self->{'task_data'}->{'interval_sweep'},
-					'id_group' => $self->{'task_data'}->{'id_group'},
-					'address' => $dbObj->get_host(),
-					'description' => '',
-				},
-				'module_data' => \@modules,
-			}
-		];
-
-		$self->call('create_agents', $data);
+		$self->call('create_agents', \@data);
 
 		# Destroy item.
 		undef($dbObj);

From ce9f9eab4e82554ee95079aea0e5e88ac64960de Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 16:00:08 +0200
Subject: [PATCH 10/31] rc1 mysql recon

Former-commit-id: 51e000229d6c2c94e59e8eeb8ef77d539ee6c775
---
 .../lib/PandoraFMS/DiscoveryServer.pm         |  4 ++--
 pandora_server/lib/PandoraFMS/Recon/Base.pm   | 20 ++++++++++++++++++-
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index c97a393422..eef7fa85f0 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -459,8 +459,8 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 			$agent_id = pandora_create_agent(
 				$pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
 				$agent->{'address'}, $agent->{'id_group'}, $parent_id,
-				$agent->{'os'}, $agent->{'description'}, $agent->{'interval'},
-				$dbh, $agent->{'timezone_offset'}
+				get_os_id($dbh, $agent->{'os'}), $agent->{'description'},
+				$agent->{'interval'}, $dbh, $agent->{'timezone_offset'}
 			);
 
 			$current_agent = $parent_id = PandoraFMS::Core::locate_agent(
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 2b04dab950..df00c10951 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1475,6 +1475,8 @@ sub db_scan($) {
 			};
 
 		} else {
+			my $dbObjCfg = $dbObj->get_config();
+
 			$self->{'summary'}->{'discovered'} += 1;
 			$self->{'summary'}->{'alive'} += 1;
 
@@ -1499,10 +1501,26 @@ sub db_scan($) {
 			push @modules, $dbObj->get_statistics();
 			$self->call('update_progress', 50);
 
-
 			# Custom queries.
 			push @modules, $dbObj->execute_custom_queries();
 			$self->call('update_progress', 90);
+
+			if (defined($dbObjCfg->{'scan_databases'})
+			&& $dbObjCfg->{'scan_databases'} == 1) {
+				my $__data = $dbObj->scan_databases();
+
+				if (ref($__data) eq "ARRAY") {
+					if (defined($dbObjCfg->{'agent_per_database'})
+					&& $dbObjCfg->{'agent_per_database'} == 1) {
+						# Agent per database detected.
+						push @data, @{$__data};
+					} else {
+						# Merge modules into engine agent.
+						my @_modules = map { $_->{'module_data'} } @{$__data};
+						push @modules, @_modules;
+					}
+				}
+			}
 		}
 
 		# Put engine agent at the beginning of the list.

From 56f2acbbf16fb6fa9815e5b579a7b27ae850f34c Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 16:05:16 +0200
Subject: [PATCH 11/31] discovery.app.mysql rc1

Former-commit-id: 51304e872d375b480cbbf88d058b1804106afb98
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index eef7fa85f0..6179fbc4c3 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -453,13 +453,18 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 		}
 
 		my $agent_id;
+		my $os_id = get_os_id($dbh, $agent->{'os'});
+
+		if (!$os_id) {
+			$os_id = get_os_id($dbh, 'Other');
+		}
 
 		if (!$current_agent) {
 			# Create agent.
 			$agent_id = pandora_create_agent(
 				$pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
 				$agent->{'address'}, $agent->{'id_group'}, $parent_id,
-				get_os_id($dbh, $agent->{'os'}), $agent->{'description'},
+				$os_id, $agent->{'description'},
 				$agent->{'interval'}, $dbh, $agent->{'timezone_offset'}
 			);
 

From 12743802705918964b3f46c66c1b88c0beeac9a7 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 16:07:50 +0200
Subject: [PATCH 12/31] minor fix

Former-commit-id: a012c8155cd1d950044bc2c0531ee2abd9e89d07
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 6179fbc4c3..52c2a53a0a 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -455,7 +455,7 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 		my $agent_id;
 		my $os_id = get_os_id($dbh, $agent->{'os'});
 
-		if (!$os_id) {
+		if ($os_id < 0) {
 			$os_id = get_os_id($dbh, 'Other');
 		}
 

From 143c501a6eab56ace3ccb5a4491979655113aea4 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 17:08:31 +0200
Subject: [PATCH 13/31] minor fixes

Former-commit-id: 8d8c891a963b0e03838c2bf184b5da6bed01b2a9
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 52c2a53a0a..f3b6f007e0 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -446,9 +446,9 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 		);
 
 		my $parent_id;
-		if (defined($agent->{'parent_agent'})) {
+		if (defined($agent->{'parent_agent_name'})) {
 			$parent_id = PandoraFMS::Core::locate_agent(
-				$pa_config, $dbh, $agent->{'parent_agent'}
+				$pa_config, $dbh, $agent->{'parent_agent_name'}
 			);
 		}
 

From e76a5af44122eafb5b00de4517cca02d0b716de8 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 4 Apr 2019 18:20:26 +0200
Subject: [PATCH 14/31] minor fix parent link

Former-commit-id: a2330dd0159ad58c454a06b7efe16699f7cee84a
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index f3b6f007e0..44cd4dcdbb 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -450,6 +450,9 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 			$parent_id = PandoraFMS::Core::locate_agent(
 				$pa_config, $dbh, $agent->{'parent_agent_name'}
 			);
+			if ($parent_id) {
+				$parent_id = $parent_id->{'id_agente'};
+			}
 		}
 
 		my $agent_id;

From db9068e25a930febc2faf0c0bfba22402d6d3385 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 5 Apr 2019 10:41:09 +0200
Subject: [PATCH 15/31] fixes in non agent per database

Former-commit-id: 180cf7269886787b17dc359bf941b5ce5e1b1313
---
 .../godmode/wizards/DiscoveryTaskList.class.php     | 13 +++++++++++++
 pandora_server/lib/PandoraFMS/Recon/Base.pm         |  5 ++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 00221aba1a..2cbe9c4f45 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -475,6 +475,16 @@ class DiscoveryTaskList extends Wizard
                             $data[6] .= __('Discovery.App.MySQL');
                         break;
 
+                        case DISCOVERY_APP_ORACLE:
+                            // Discovery Applications Oracle.
+                            $data[6] = html_print_image(
+                                'images/network.png',
+                                true,
+                                ['title' => __('Discovery Applications Oracle')]
+                            ).'&nbsp;&nbsp;';
+                            $data[6] .= __('Discovery.App.Oracle');
+                        break;
+
                         case DISCOVERY_HOSTDEVICES:
                         default:
                             // Discovery NetScan.
@@ -631,6 +641,9 @@ class DiscoveryTaskList extends Wizard
             case DISCOVERY_APP_MYSQL:
             return 'wiz=app&mode=mysql&page=0';
 
+            case DISCOVERY_APP_ORACLE:
+            return 'wiz=app&mode=oracle&page=0';
+
             case DISCOVERY_APP_VMWARE:
             return 'wiz=app&mode=vmware&page=0';
 
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index df00c10951..6df41c4f92 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1516,7 +1516,10 @@ sub db_scan($) {
 						push @data, @{$__data};
 					} else {
 						# Merge modules into engine agent.
-						my @_modules = map { $_->{'module_data'} } @{$__data};
+						my @_modules = map { 
+							map { $_ } @{$_->{'module_data'}}
+						} @{$__data};
+
 						push @modules, @_modules;
 					}
 				}

From 970a10ba504d31791bc565988bd4a086c9a2f6c5 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 5 Apr 2019 10:41:37 +0200
Subject: [PATCH 16/31] fixes in non agent per database

Former-commit-id: 7b34ea990bf52c96d4d6f65f11cf2949c199f2db
---
 .../godmode/wizards/DiscoveryTaskList.class.php  | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 2cbe9c4f45..9d1242f989 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -96,8 +96,20 @@ class DiscoveryTaskList extends Wizard
             ]
         );
 
-        // Header
-        ui_print_page_header(__('Task list'), '', false, '', true, '', false, '', GENERIC_SIZE_TEXT, '', $this->printHeader(true));
+        // Header.
+        ui_print_page_header(
+            __('Task list'),
+            '',
+            false,
+            '',
+            true,
+            '',
+            false,
+            '',
+            GENERIC_SIZE_TEXT,
+            '',
+            $this->printHeader(true)
+        );
 
         // Show redirected messages from discovery.php.
         if ($status === 0) {

From 4808e4ae9735263afd1440d4ab9e2f29c9dc7ac2 Mon Sep 17 00:00:00 2001
From: Daniel Barbero <daniel.barbero@artica.es>
Date: Fri, 5 Apr 2019 16:43:36 +0200
Subject: [PATCH 17/31] fixed errors map ipam

Former-commit-id: 9a1e5460ab40d22135edc75f2adf186f8d56f3d4
---
 pandora_console/include/class/NetworkMap.class.php | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index dba51499f4..c1061fe120 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -1616,6 +1616,16 @@ class NetworkMap
 
             if (is_array($node['style']) === false) {
                 $node['style'] = json_decode($node['style'], true);
+
+                // Add styles.
+                if (isset($source_data['style']) === true
+                    && is_array($source_data['style']) === true
+                ) {
+                    $node['style'] = array_merge(
+                        $node['style'],
+                        $source_data['style']
+                    );
+                }
             }
 
             // Propagate styles.
@@ -2722,6 +2732,7 @@ class NetworkMap
         }
 
         $this->nodesJS = $this->nodesToJS($nodes);
+
         $output .= 'networkmap.nodes = ('.json_encode($this->nodesJS).");\n";
 
         // Clean.

From b9db5fdb6f7092d8fb717b56f8403bce3353da5e Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 5 Apr 2019 17:20:45 +0200
Subject: [PATCH 18/31] wip discovery f3

Former-commit-id: 6b9f5bc3995a16414e1c1a9201983f33eb6908ad
---
 pandora_server/lib/PandoraFMS/Recon/Base.pm | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 6df41c4f92..8e18f659e8 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1468,10 +1468,10 @@ sub db_scan($) {
 			call('message', 'Cannot connect to target ' . $target, 3);
 			$self->{'summary'}->{'not_alive'} += 1;
 			push @modules, {
-				name => 'mysql_connection',
+				name => $type . ' connection',
 				type => 'generic_proc',
 				data => 0,
-				description => 'MySQL availability'
+				description => $type . ' availability'
 			};
 
 		} else {
@@ -1481,10 +1481,10 @@ sub db_scan($) {
 			$self->{'summary'}->{'alive'} += 1;
 
 			push @modules, {
-				name => 'mysql_connection',
+				name => $type . ' connection',
 				type => 'generic_proc',
 				data => 1,
-				description => 'MySQL availability'
+				description => $type . ' availability'
 			};
 
 			# Analyze.
@@ -1527,11 +1527,12 @@ sub db_scan($) {
 		}
 
 		# Put engine agent at the beginning of the list.
+		my $version = $dbObj->get_version();
 		unshift @data,{
 			'agent_data' => {
 				'agent_name' => $dbObj->get_agent_name(),
 				'os' => $type,
-				'os_version' => 'Discovery',
+				'os_version' => (defined($version) ? $version : 'Discovery'),
 				'interval' => $self->{'task_data'}->{'interval_sweep'},
 				'id_group' => $self->{'task_data'}->{'id_group'},
 				'address' => $dbObj->get_host(),

From 54bd3bf08954d4b51fed59dbd3b110b503a14322 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 8 Apr 2019 16:23:32 +0200
Subject: [PATCH 19/31] Discovery F3

Former-commit-id: 1990149c5f5795f825bc337fd7ae29d360348d45
---
 .../lib/PandoraFMS/DiscoveryServer.pm         |  2 +-
 pandora_server/lib/PandoraFMS/Recon/Base.pm   | 33 +++++++++++++++++--
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 44cd4dcdbb..8e268f78cc 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -494,7 +494,7 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 
 		# Update agent information
 		pandora_update_agent(
-			$pa_config, time(), $agent_id,
+			$pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id,
 			$agent->{'os_version'}, $agent->{'agent_version'},
 			$agent->{'interval'}, $dbh, undef, $parent_id
 		);
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 8e18f659e8..97b239ce95 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1448,16 +1448,28 @@ sub db_scan($) {
 
 	my @targets = split /,/, $self->{'task_data'}->{'subnet'};
 
+	my $global_step = 100 / (scalar @targets);
+	my $global_percent = 0;
 	my $i = 0;
 	foreach my $target (@targets) {
 		my @data;
 		my @modules;
+
+		$self->{'step'} = STEP_DATABASE_SCAN;
+		$self->{'c_network_name'} = $target;
+		$self->{'c_network_percent'} = 0;
+
+		# Send message
 		call('message', 'Checking target ' . $target, 10);
 
 		# Force target acquirement.
 		$self->{'task_data'}->{'dbhost'} = $target;
 		$self->{'task_data'}->{'target_index'} = $i++;
 
+		# Update progress
+		$self->{'c_network_percent'} = 10;
+		$self->call('update_progress', $global_percent + (10 / (scalar @targets)));
+
 		# Connect to target.
 		my $dbObj = PandoraFMS::Recon::Util::enterprise_new(
 			'PandoraFMS::Recon::Applications::'.$type,
@@ -1466,6 +1478,10 @@ sub db_scan($) {
 
 		if (!$dbObj->is_connected()) {
 			call('message', 'Cannot connect to target ' . $target, 3);
+			$global_percent += $global_step;
+			$self->{'c_network_percent'} = 90;
+			# Update progress
+			$self->call('update_progress', $global_percent + (90 / (scalar @targets)));
 			$self->{'summary'}->{'not_alive'} += 1;
 			push @modules, {
 				name => $type . ' connection',
@@ -1489,8 +1505,9 @@ sub db_scan($) {
 
 			# Analyze.
 			$self->{'step'} = STEP_STATISTICS;
+			$self->{'c_network_percent'} = 30;
+			$self->call('update_progress', $global_percent + (30 / (scalar @targets)));
 			$self->{'c_network_name'} = $dbObj->get_host();
-			$self->call('update_progress', 10);
 
 			# Retrieve connection statistics.
 			# Retrieve uptime statistics
@@ -1498,15 +1515,21 @@ sub db_scan($) {
 			# Retrieve connections
 			# Retrieve innodb
 			# Retrieve cache
+			$self->{'c_network_percent'} = 50;
+			$self->call('update_progress', $global_percent + (50 / (scalar @targets)));
 			push @modules, $dbObj->get_statistics();
-			$self->call('update_progress', 50);
 
 			# Custom queries.
+			$self->{'step'} = STEP_CUSTOM_QUERIES;
+			$self->{'c_network_percent'} = 80;
+			$self->call('update_progress', $global_percent + (80 / (scalar @targets)));
 			push @modules, $dbObj->execute_custom_queries();
-			$self->call('update_progress', 90);
 
 			if (defined($dbObjCfg->{'scan_databases'})
 			&& $dbObjCfg->{'scan_databases'} == 1) {
+				# Skip database scan in Oracle tasks
+				next if $self->{'type'} == DISCOVERY_APP_ORACLE;
+
 				my $__data = $dbObj->scan_databases();
 
 				if (ref($__data) eq "ARRAY") {
@@ -1545,6 +1568,10 @@ sub db_scan($) {
 
 		# Destroy item.
 		undef($dbObj);
+
+		$global_percent += $global_step;
+		$self->{'c_network_percent'} = 100;
+		$self->call('update_progress', $global_percent);
 	}
 
 	# Update progress.

From d5b1ac556522aad498ce216ae9478ee64f33aea7 Mon Sep 17 00:00:00 2001
From: Daniel Barbero Martin <daniel.barbero@artica.es>
Date: Mon, 8 Apr 2019 18:28:27 +0200
Subject: [PATCH 20/31] fixed map IPAM

Former-commit-id: a1334a1691a3e861f2510ac7d440f5730928ad9a
---
 .../include/class/NetworkMap.class.php        | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index c1061fe120..fd7274b94f 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -1242,6 +1242,11 @@ class NetworkMap
             return '';
         }
 
+        if ($this->mapOptions['fixed_positions']) {
+            // Ignore.
+            return;
+        }
+
         $dot_str = '';
 
         // Color is being printed by D3, not graphviz.
@@ -1259,6 +1264,15 @@ class NetworkMap
 
         $radius /= GRAPHVIZ_CONVERSION_FACTOR;
 
+        if (is_array($label)) {
+            $label = array_reduce(
+                function ($carry, $item) {
+                    $carry .= $item;
+                    return $carry;
+                }
+            );
+        }
+
         if (strlen($label) > 16) {
             $label = ui_print_truncate_text($label, 16, false, true, false);
         }
@@ -2079,6 +2093,10 @@ class NetworkMap
                         'id_source' => $id_source,
                         'label'     => $label,
                         'image'     => null,
+                        'radius'    => max(
+                            $node['width'],
+                            $node['height']
+                        ),
                     ]
                 );
 
@@ -2454,6 +2472,8 @@ class NetworkMap
             $this->map['height'] = $this->mapOptions['height'];
         }
 
+        $this->map['filter']['z_dash'] = $this->mapOptions['z_dash'];
+
         if (is_array($graph) === true) {
             $nodes = $graph['nodes'];
             $relations = $graph['relations'];

From e59ce5412c8b41db770459d872e76fd116d406c5 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Tue, 9 Apr 2019 18:33:02 +0200
Subject: [PATCH 21/31] WIP Discovery RDS

Former-commit-id: fba3f7dbd44ca131404aa2d3986d3925b9754382
---
 .../godmode/wizards/HostDevices.class.php     | 17 ++++-
 .../godmode/wizards/Wizard.main.php           | 37 ++++------
 .../include/functions_snmp_browser.php        | 67 ++++++++++++-------
 pandora_server/lib/PandoraFMS/Recon/Base.pm   |  6 +-
 4 files changed, 75 insertions(+), 52 deletions(-)

diff --git a/pandora_console/godmode/wizards/HostDevices.class.php b/pandora_console/godmode/wizards/HostDevices.class.php
index e4e0e97fdc..b46828c271 100755
--- a/pandora_console/godmode/wizards/HostDevices.class.php
+++ b/pandora_console/godmode/wizards/HostDevices.class.php
@@ -149,7 +149,8 @@ class HostDevices extends Wizard
                         ),
                         'label' => __('Discovery'),
                     ],
-                ]
+                ],
+                true
             );
 
             ui_print_page_header(__('Host & devices'), '', false, '', true, '', false, '', GENERIC_SIZE_TEXT, '', $this->printHeader(true));
@@ -533,7 +534,19 @@ class HostDevices extends Wizard
         if ($this->page < $this->maxPagesNetScan) {
             // Avoid to print header out of wizard.
             $this->prepareBreadcrum($breadcrum);
-            ui_print_page_header(__('NetScan'), '', false, '', true, '', false, '', GENERIC_SIZE_TEXT, '', $this->printHeader(true));
+            ui_print_page_header(
+                __('NetScan'),
+                '',
+                false,
+                '',
+                true,
+                '',
+                false,
+                '',
+                GENERIC_SIZE_TEXT,
+                '',
+                $this->printHeader(true)
+            );
         }
 
         if (isset($this->page) === true
diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php
index d8a829e277..f043f143db 100644
--- a/pandora_console/godmode/wizards/Wizard.main.php
+++ b/pandora_console/godmode/wizards/Wizard.main.php
@@ -191,21 +191,20 @@ class Wizard
      * Builder for breadcrum
      *
      * @param array   $urls Array of urls to be stored in breadcrum.
-     * @param boolean $add  True if breadcrum should be added instead of
-     *      overwrite it.
+     * @param boolean $add  True if breadcrum should be added
+     *                      instead of overwrite it.
      *
      * @return void
      */
-    public function prepareBreadcrum(array $urls, bool $add=false, bool $separator_beginning=false)
-    {
+    public function prepareBreadcrum(
+        array $urls,
+        bool $add=false
+    ) {
         $bc = [];
         $i = 0;
-        $count = 0;
-        $array_size = count($urls);
+        $array_size = (count($urls) - 1);
 
         foreach ($urls as $url) {
-            $count++;
-
             if ($url['selected'] == 1) {
                 $class = 'selected';
             } else {
@@ -213,20 +212,10 @@ class Wizard
             }
 
             $bc[$i] = '';
-
-            if ($separator_beginning === true) {
-                $bc[$i] .= '<span class="breadcrumb_link">&nbsp/&nbsp</span>';
-            }
-
-            $bc[$i]   .= '<span><a class="breadcrumb_link '.$class.'" href="'.$url['link'].'">';
-            $bc[$i]   .= $url['label'];
-            $bc[$i]   .= '</a>';
-            if ($count < $array_size) {
-                $bc[$i] .= '<span class="breadcrumb_link">&nbsp/&nbsp</span>';
-            }
-
+            $bc[$i] .= '<span><a class="breadcrumb_link '.$class.'" href="'.$url['link'].'">';
+            $bc[$i] .= $url['label'];
+            $bc[$i] .= '</a>';
             $bc[$i] .= '</span>';
-
             $i++;
         }
 
@@ -235,7 +224,6 @@ class Wizard
         } else {
             $this->setBreadcrum($bc);
         }
-
     }
 
 
@@ -275,7 +263,10 @@ class Wizard
      */
     public function printBreadcrum()
     {
-        return implode('', $this->breadcrum);
+        return implode(
+            '<span class="breadcrumb_link">&nbsp/&nbsp</span>',
+            $this->breadcrum
+        );
     }
 
 
diff --git a/pandora_console/include/functions_snmp_browser.php b/pandora_console/include/functions_snmp_browser.php
index fd68b77e54..d22dd5dc1e 100644
--- a/pandora_console/include/functions_snmp_browser.php
+++ b/pandora_console/include/functions_snmp_browser.php
@@ -54,10 +54,13 @@ function snmp_browser_print_tree(
     $last=0,
     $last_array=[],
     $sufix=false,
-    $checked=[]
+    $checked=[],
+    $return=false
 ) {
     static $url = false;
 
+    $output = '';
+
     // Get the base URL for images.
     if ($url === false) {
         $url = ui_get_full_url('operation/tree', false, false, false);
@@ -73,9 +76,9 @@ function snmp_browser_print_tree(
     $last_array[$depth] = $last;
 
     if ($depth > 0) {
-        echo "<ul id='ul_$id' style='margin: 0; padding: 0; display: none'>\n";
+        $output .= "<ul id='ul_$id' style='margin: 0; padding: 0; display: none'>\n";
     } else {
-        echo "<ul id='ul_$id' style='margin: 0; padding: 0;'>\n";
+        $output .= "<ul id='ul_$id' style='margin: 0; padding: 0;'>\n";
     }
 
     foreach ($tree['__LEAVES__'] as $level => $sub_level) {
@@ -83,73 +86,89 @@ function snmp_browser_print_tree(
         $sub_id = time().rand(0, getrandmax());
 
         // Display the branch.
-        echo "<li id='li_$sub_id' style='margin: 0; padding: 0;'>";
+        $output .= "<li id='li_$sub_id' style='margin: 0; padding: 0;'>";
 
         // Indent sub branches.
         for ($i = 1; $i <= $depth; $i++) {
             if ($last_array[$i] == 1) {
-                echo '<img src="'.$url.'/no_branch.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/no_branch.png" style="vertical-align: middle;">';
             } else {
-                echo '<img src="'.$url.'/branch.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/branch.png" style="vertical-align: middle;">';
             }
         }
 
         // Branch.
         if (! empty($sub_level['__LEAVES__'])) {
-            echo "<a id='anchor_$sub_id' onfocus='javascript: this.blur();' href='javascript: toggleTreeNode(\"$sub_id\", \"$id\");'>";
+            $output .= "<a id='anchor_$sub_id' onfocus='javascript: this.blur();' href='javascript: toggleTreeNode(\"$sub_id\", \"$id\");'>";
             if ($depth == 0 && $count == 0) {
                 if ($count == $total) {
-                    echo '<img src="'.$url.'/one_closed.png" style="vertical-align: middle;">';
+                    $output .= '<img src="'.$url.'/one_closed.png" style="vertical-align: middle;">';
                 } else {
-                    echo '<img src="'.$url.'/first_closed.png" style="vertical-align: middle;">';
+                    $output .= '<img src="'.$url.'/first_closed.png" style="vertical-align: middle;">';
                 }
             } else if ($count == $total) {
-                echo '<img src="'.$url.'/last_closed.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/last_closed.png" style="vertical-align: middle;">';
             } else {
-                echo '<img src="'.$url.'/closed.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/closed.png" style="vertical-align: middle;">';
             }
 
-            echo '</a>';
+            $output .= '</a>';
         }
+
         // Leave.
         else {
             if ($depth == 0 && $count == 0) {
                 if ($count == $total) {
-                    echo '<img src="'.$url.'/no_branch.png" style="vertical-align: middle;">';
+                    $output .= '<img src="'.$url.'/no_branch.png" style="vertical-align: middle;">';
                 } else {
-                    echo '<img src="'.$url.'/first_leaf.png" style="vertical-align: middle;">';
+                    $output .= '<img src="'.$url.'/first_leaf.png" style="vertical-align: middle;">';
                 }
             } else if ($count == $total) {
-                echo '<img src="'.$url.'/last_leaf.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/last_leaf.png" style="vertical-align: middle;">';
             } else {
-                echo '<img src="'.$url.'/leaf.png" style="vertical-align: middle;">';
+                $output .= '<img src="'.$url.'/leaf.png" style="vertical-align: middle;">';
             }
         }
 
         // Branch or leave with branches!
         if (isset($sub_level['__OID__'])) {
-            echo "<a onfocus='javascript: this.blur();' href='javascript: snmpGet(\"".addslashes($sub_level['__OID__'])."\");'>";
-            echo '<img src="'.$url.'/../../images/eye.png" style="vertical-align: middle;">';
-            echo '</a>';
+            $output .= "<a onfocus='javascript: this.blur();' href='javascript: snmpGet(\"".addslashes($sub_level['__OID__'])."\");'>";
+            $output .= '<img src="'.$url.'/../../images/eye.png" style="vertical-align: middle;">';
+            $output .= '</a>';
         }
 
         $checkbox_name_sufix = ($sufix === true) ? '_'.$level : '';
         $checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
         $status = (!empty($checked) && isset($checked[$level]));
-        echo html_print_checkbox($checkbox_name, 0, $status, true, false, '').'&nbsp;<span>'.$level.'</span>';
+        $output .= html_print_checkbox($checkbox_name, 0, $status, true, false, '').'&nbsp;<span>'.$level.'</span>';
         if (isset($sub_level['__VALUE__'])) {
-            echo '<span class="value" style="display: none;">&nbsp;=&nbsp;'.$sub_level['__VALUE__'].'</span>';
+            $output .= '<span class="value" style="display: none;">&nbsp;=&nbsp;'.$sub_level['__VALUE__'].'</span>';
         }
 
-        echo '</li>';
+        $output .= '</li>';
 
         // Recursively print sub levels.
-        snmp_browser_print_tree($sub_level, $sub_id, ($depth + 1), ($count == $total ? 1 : 0), $last_array, $sufix, $checked);
+        $output .= snmp_browser_print_tree(
+            $sub_level,
+            $sub_id,
+            ($depth + 1),
+            ($count == $total ? 1 : 0),
+            $last_array,
+            $sufix,
+            $checked,
+            $return
+        );
 
         $count++;
     }
 
-    echo '</ul>';
+    $output .= '</ul>';
+
+    if ($return == false) {
+        echo $output;
+    }
+
+    return $output;
 }
 
 
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 97b239ce95..afc677c15a 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1427,9 +1427,9 @@ sub scan_subnet($) {
 }
 
 ##########################################################################
-# Perform a DB scan.
+# Perform an Application scan.
 ##########################################################################
-sub db_scan($) {
+sub app_scan($) {
 	my ($self) = @_;
 	my ($progress, $step);
 
@@ -1595,7 +1595,7 @@ sub scan($) {
 		if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL
 		||  $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) {
 			# Database scan.
-			return $self->db_scan();
+			return $self->app_scan();
 		}
 	}
 

From 834d5d6c50b485db2d3c93fe65460de4cfc2592d Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 10 Apr 2019 20:40:03 +0200
Subject: [PATCH 22/31] WIP:Discovery RDS

Former-commit-id: d53eb29ec8e7c70c1c76918c1770f65ad81f8ba0
---
 .../wizards/DiscoveryTaskList.class.php       |    3 +
 .../lib/PandoraFMS/DiscoveryServer.pm         | 1439 +++++++++--------
 pandora_server/lib/PandoraFMS/Recon/Base.pm   |   57 +-
 3 files changed, 788 insertions(+), 711 deletions(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 9d1242f989..20b52c7e36 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -662,6 +662,9 @@ class DiscoveryTaskList extends Wizard
             case DISCOVERY_CLOUD_AWS:
             return 'wiz=cloud&mode=amazonws&page=1';
 
+            case DISCOVERY_CLOUD_AWS_RDS:
+            return 'wiz=cloud&mode=amazonws&sub=rds&page=0';
+
             case 'console_task':
             return 'wiz=ctask';
 
diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 8e268f78cc..681355011a 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -53,369 +53,388 @@ my $Sem :shared;
 my $TaskSem :shared;
 
 # IDs from tconfig_os.
-use constant OS_OTHER => 10;
-use constant OS_ROUTER => 17;
-use constant OS_SWITCH => 18;
+use constant {
+    OS_OTHER => 10,
+    OS_ROUTER => 17,
+    OS_SWITCH => 18,
+    DISCOVERY_HOSTDEVICES => 0,
+    DISCOVERY_HOSTDEVICES_CUSTOM => 1,
+    DISCOVERY_CLOUD_AWS => 2,
+    DISCOVERY_APP_VMWARE => 3,
+    DISCOVERY_APP_MYSQL => 4,
+    DISCOVERY_APP_ORACLE => 5,
+    DISCOVERY_CLOUD_AWS_EC2 => 6,
+    DISCOVERY_CLOUD_AWS_RDS => 7
+};
 
 ########################################################################################
 # Discovery Server class constructor.
 ########################################################################################
 sub new ($$$$$$) {
-	my ($class, $config, $dbh) = @_;
-	
-	return undef unless $config->{'reconserver'} == 1 || $config->{'discoveryserver'} == 1;
-	
-	if (! -e $config->{'nmap'}) {
-		logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
-		print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
-		return undef;
-	}
+    my ($class, $config, $dbh) = @_;
+    
+    return undef unless $config->{'reconserver'} == 1 || $config->{'discoveryserver'} == 1;
+    
+    if (! -e $config->{'nmap'}) {
+        logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
+        print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
+        return undef;
+    }
 
-	# Initialize semaphores and queues
-	@TaskQueue = ();
-	%PendingTasks = ();
-	$Sem = Thread::Semaphore->new;
-	$TaskSem = Thread::Semaphore->new (0);
-	
-	# Restart automatic recon tasks.
-	db_do ($dbh, 'UPDATE trecon_task  SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0',
-	       get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
+    # Initialize semaphores and queues
+    @TaskQueue = ();
+    %PendingTasks = ();
+    $Sem = Thread::Semaphore->new;
+    $TaskSem = Thread::Semaphore->new (0);
+    
+    # Restart automatic recon tasks.
+    db_do ($dbh, 'UPDATE trecon_task  SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0',
+           get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
 
-	# Reset (but do not restart) manual recon tasks.
-	db_do ($dbh, 'UPDATE trecon_task  SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0',
-	       get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
+    # Reset (but do not restart) manual recon tasks.
+    db_do ($dbh, 'UPDATE trecon_task  SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0',
+           get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
 
-	# Call the constructor of the parent class
-	my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh);
-	
-	bless $self, $class;
-	return $self;
+    # Call the constructor of the parent class
+    my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh);
+    
+    bless $self, $class;
+    return $self;
 }
 
 ###############################################################################
 # Run.
 ###############################################################################
 sub run ($) {
-	my $self = shift;
-	my $pa_config = $self->getConfig ();
-	
-	print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1);
-	my $threads = $pa_config->{'recon_threads'};
+    my $self = shift;
+    my $pa_config = $self->getConfig ();
+    
+    print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1);
+    my $threads = $pa_config->{'recon_threads'};
 
-	# Use hightest value
-	if ($pa_config->{'discovery_threads'}  > $pa_config->{'recon_threads'}) {
-		$threads = $pa_config->{'discovery_threads'};
-	}
-	$self->setNumThreads($threads);
-	$self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
+    # Use hightest value
+    if ($pa_config->{'discovery_threads'}  > $pa_config->{'recon_threads'}) {
+        $threads = $pa_config->{'discovery_threads'};
+    }
+    $self->setNumThreads($threads);
+    $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
 }
 
 ###############################################################################
 # Data producer.
 ###############################################################################
 sub data_producer ($) {
-	my $self = shift;
-	my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
-	
-	my @tasks;
-	
-	my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ());
-	return @tasks unless defined ($server_id);
-	
-	# Manual tasks have interval_sweep = 0
-	# Manual tasks are "forced" like the other, setting the utimestamp to 1
-	# By default, after create a tasks it takes the utimestamp to 0
-	# Status -1 means "done".
-	
-	my @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task 
-		WHERE id_recon_server = ?
-		AND disabled = 0
-		AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
-			OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
-	foreach my $row (@rows) {
-		
-		# Update task status
-		update_recon_task ($dbh, $row->{'id_rt'}, 1);
-		
-		push (@tasks, $row->{'id_rt'});
-	}
-	
-	return @tasks;
+    my $self = shift;
+    my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
+    
+    my @tasks;
+    
+    my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ());
+    return @tasks unless defined ($server_id);
+    
+    # Manual tasks have interval_sweep = 0
+    # Manual tasks are "forced" like the other, setting the utimestamp to 1
+    # By default, after create a tasks it takes the utimestamp to 0
+    # Status -1 means "done".
+    
+    my @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task 
+        WHERE id_recon_server = ?
+        AND disabled = 0
+        AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
+            OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
+    foreach my $row (@rows) {
+        
+        # Update task status
+        update_recon_task ($dbh, $row->{'id_rt'}, 1);
+        
+        push (@tasks, $row->{'id_rt'});
+    }
+    
+    return @tasks;
 }
 
 ###############################################################################
 # Data consumer.
 ###############################################################################
 sub data_consumer ($$) {
-	my ($self, $task_id) = @_;
-	my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
+    my ($self, $task_id) = @_;
+    my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
 
-	# Get server id.
-	my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType());
+    # Get server id.
+    my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType());
 
-	# Get recon task data	
-	my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id);	
-	return -1 unless defined ($task);
+    # Get recon task data	
+    my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id);	
+    return -1 unless defined ($task);
 
-	# Is it a recon script?
-	if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) {
-		exec_recon_script ($pa_config, $dbh, $task);
-		return;
-	} else {
-		logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10);
-	}
+    # Is it a recon script?
+    if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) {
+        exec_recon_script ($pa_config, $dbh, $task);
+        return;
+    } else {
+        logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10);
+    }
 
-	eval {
-		my @subnets = split(/,/, safe_output($task->{'subnet'}));
-		my @communities = split(/,/, safe_output($task->{'snmp_community'}));
-		my @auth_strings = ();
-		if(defined($task->{'auth_strings'})) {
-			@auth_strings = split(/,/, safe_output($task->{'auth_strings'}));
-		}
+    eval {
+        my @subnets = split(/,/, safe_output($task->{'subnet'}));
+        my @communities = split(/,/, safe_output($task->{'snmp_community'}));
+        my @auth_strings = ();
+        if(defined($task->{'auth_strings'})) {
+            @auth_strings = split(/,/, safe_output($task->{'auth_strings'}));
+        }
 
-		my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh);
+        my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh);
 
-		my $recon = new PandoraFMS::Recon::Base(
-			communities => \@communities,
-			dbh => $dbh,
-			group_id => $task->{'id_group'},
-			id_os => $task->{'id_os'},
-			id_network_profile => $task->{'id_network_profile'},
-			os_detection => $task->{'os_detect'},
-			parent_detection => $task->{'parent_detection'},
-			parent_recursion => $task->{'parent_recursion'},
-			pa_config => $pa_config,
-			recon_ports => $task->{'recon_ports'},
-			resolve_names => $task->{'resolve_names'},
-			snmp_auth_user => $task->{'snmp_auth_user'},
-			snmp_auth_pass => $task->{'snmp_auth_pass'},
-			snmp_auth_method => $task->{'snmp_auth_method'},
-			snmp_checks => $task->{'snmp_checks'},
-			snmp_enabled => $task->{'snmp_enabled'},
-			snmp_privacy_method => $task->{'snmp_privacy_method'},
-			snmp_privacy_pass => $task->{'snmp_privacy_pass'},
-			snmp_security_level => $task->{'snmp_security_level'},
-			snmp_timeout => $task->{'snmp_timeout'},
-			snmp_version => $task->{'snmp_version'},
-			subnets => \@subnets,
-			task_id => $task->{'id_rt'},
-			vlan_cache_enabled => $task->{'vlan_enabled'},
-			wmi_enabled => $task->{'wmi_enabled'},
-			auth_strings_array => \@auth_strings,
-			autoconfiguration_enabled => $task->{'autoconfiguration_enabled'},
-			main_event_id => $main_event,
-			server_id => $server_id,
-			%{$pa_config},
-			task_data => $task
-		);
+        my %cnf_extra;
+        if ($task->{'type'} == DISCOVERY_CLOUD_AWS_EC2
+        || $task->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+            $cnf_extra{'aws_access_key_id'} = pandora_get_config_value($dbh, 'aws_access_key_id');
+            $cnf_extra{'aws_secret_access_key'} = pandora_get_config_value($dbh, 'aws_secret_access_key');
+            $cnf_extra{'cloud_util_path'} = pandora_get_config_value($dbh, 'cloud_util_path');
+        }
 
-		$recon->scan();
-	};
-	if ($@) {
-		update_recon_task ($dbh, $task_id, -1);
-		return;
-	}
+        my $recon = new PandoraFMS::Recon::Base(
+            communities => \@communities,
+            dbh => $dbh,
+            group_id => $task->{'id_group'},
+            id_os => $task->{'id_os'},
+            id_network_profile => $task->{'id_network_profile'},
+            os_detection => $task->{'os_detect'},
+            parent_detection => $task->{'parent_detection'},
+            parent_recursion => $task->{'parent_recursion'},
+            pa_config => $pa_config,
+            recon_ports => $task->{'recon_ports'},
+            resolve_names => $task->{'resolve_names'},
+            snmp_auth_user => $task->{'snmp_auth_user'},
+            snmp_auth_pass => $task->{'snmp_auth_pass'},
+            snmp_auth_method => $task->{'snmp_auth_method'},
+            snmp_checks => $task->{'snmp_checks'},
+            snmp_enabled => $task->{'snmp_enabled'},
+            snmp_privacy_method => $task->{'snmp_privacy_method'},
+            snmp_privacy_pass => $task->{'snmp_privacy_pass'},
+            snmp_security_level => $task->{'snmp_security_level'},
+            snmp_timeout => $task->{'snmp_timeout'},
+            snmp_version => $task->{'snmp_version'},
+            subnets => \@subnets,
+            task_id => $task->{'id_rt'},
+            vlan_cache_enabled => $task->{'vlan_enabled'},
+            wmi_enabled => $task->{'wmi_enabled'},
+            auth_strings_array => \@auth_strings,
+            autoconfiguration_enabled => $task->{'autoconfiguration_enabled'},
+            main_event_id => $main_event,
+            server_id => $server_id,
+            %{$pa_config},
+            task_data => $task,
+            %cnf_extra
+        );
+
+        $recon->scan();
+    };
+    if ($@) {
+        update_recon_task ($dbh, $task_id, -1);
+        return;
+    }
 }
 
 ##########################################################################
 # Update recon task status.
 ##########################################################################
 sub update_recon_task ($$$) {
-	my ($dbh, $id_task, $status) = @_;
-	
-	db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task);
+    my ($dbh, $id_task, $status) = @_;
+    
+    db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task);
 } 
 
 ##########################################################################
 # Executes recon scripts
 ##########################################################################	
 sub exec_recon_script ($$$) {
-	my ($pa_config, $dbh, $task) = @_;
-	
-	# Get recon plugin data	
-	my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'});
-	return -1 unless defined ($script);
-	
-	logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10);
-	
-	my $command = safe_output($script->{'script'});
-	
-	my $macros = safe_output($task->{'macros'});
+    my ($pa_config, $dbh, $task) = @_;
+    
+    # Get recon plugin data	
+    my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'});
+    return -1 unless defined ($script);
+    
+    logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10);
+    
+    my $command = safe_output($script->{'script'});
+    
+    my $macros = safe_output($task->{'macros'});
 
-	# \r and \n should be escaped for decode_json().
-	$macros =~ s/\n/\\n/g;
-	$macros =~ s/\r/\\r/g;
-	my $decoded_macros;
-	
-	if ($macros) {
-		eval {
-			$decoded_macros = decode_json(encode_utf8($macros));
-		};
-	}
-	
-	my $macros_parameters = '';
-	
-	# Add module macros as parameter
-	if(ref($decoded_macros) eq "HASH") {
-		# Convert the hash to a sorted array
-		my @sorted_macros;
-		while (my ($i, $m) = each (%{$decoded_macros})) {
-			$sorted_macros[$i] = $m;
-		}
+    # \r and \n should be escaped for decode_json().
+    $macros =~ s/\n/\\n/g;
+    $macros =~ s/\r/\\r/g;
+    my $decoded_macros;
+    
+    if ($macros) {
+        eval {
+            $decoded_macros = decode_json(encode_utf8($macros));
+        };
+    }
+    
+    my $macros_parameters = '';
+    
+    # Add module macros as parameter
+    if(ref($decoded_macros) eq "HASH") {
+        # Convert the hash to a sorted array
+        my @sorted_macros;
+        while (my ($i, $m) = each (%{$decoded_macros})) {
+            $sorted_macros[$i] = $m;
+        }
 
-		# Remove the 0 position		
-		shift @sorted_macros;
+        # Remove the 0 position		
+        shift @sorted_macros;
 
-		foreach my $m (@sorted_macros) {
-			$macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"';
-		}
-	}
+        foreach my $m (@sorted_macros) {
+            $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"';
+        }
+    }
 
-	my $ent_script = 0;
-	my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]);
-	if (!$args) {
-		$args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters";
-	} else {
-		$ent_script = 1;
-	}
-	
-	if (-x $command) {
-		my $exec_output = `$command $args`;
-		logger($pa_config, "Execution output: \n". $exec_output, 10);
-	} else {
-		logger($pa_config, "Cannot execute recon task command $command.", 10);
-	}
-	
-	# Only update the timestamp in case something went wrong. The script should set the status.
-	db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'});
+    my $ent_script = 0;
+    my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]);
+    if (!$args) {
+        $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters";
+    } else {
+        $ent_script = 1;
+    }
+    
+    if (-x $command) {
+        my $exec_output = `$command $args`;
+        logger($pa_config, "Execution output: \n". $exec_output, 10);
+    } else {
+        logger($pa_config, "Cannot execute recon task command $command.", 10);
+    }
+    
+    # Only update the timestamp in case something went wrong. The script should set the status.
+    db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'});
 
-	if ($ent_script == 1) {
-		enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]);
-	}
-	
-	logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10);
-	return 0;
+    if ($ent_script == 1) {
+        enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]);
+    }
+    
+    logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10);
+    return 0;
 }
 
 ##########################################################################
 # Guess the OS using xprobe2 or nmap.
 ##########################################################################
 sub PandoraFMS::Recon::Base::guess_os($$) {
-	my ($self, $device) = @_;
+    my ($self, $device) = @_;
 
-	# OS detection disabled. Use the device type.
-	if ($self->{'os_detection'} == 0) {
-		my $device_type = $self->get_device_type($device);
-		return OS_OTHER unless defined($device_type);
+    # OS detection disabled. Use the device type.
+    if ($self->{'os_detection'} == 0) {
+        my $device_type = $self->get_device_type($device);
+        return OS_OTHER unless defined($device_type);
 
-		return OS_ROUTER if ($device_type eq 'router');
-		return OS_SWITCH if ($device_type eq 'switch');
-		return OS_OTHER;
-	}
+        return OS_ROUTER if ($device_type eq 'router');
+        return OS_SWITCH if ($device_type eq 'switch');
+        return OS_OTHER;
+    }
 
-	# Use xprobe2 if available
-	if (-e $self->{pa_config}->{xprobe2}) {
-			my $output = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL | grep 'Running OS' | head -1`;
-			return OS_OTHER if ($? != 0);
-			return pandora_get_os($self->{'dbh'}, $output);
-	}
-	
-	# Use nmap by default
-	if (-e $self->{pa_config}->{nmap}) {
-		my $output = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL | grep 'Aggressive OS guesses'`;
-		return OS_OTHER if ($? != 0);
-		return pandora_get_os($self->{'dbh'}, $output);
-	}
+    # Use xprobe2 if available
+    if (-e $self->{pa_config}->{xprobe2}) {
+            my $output = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL | grep 'Running OS' | head -1`;
+            return OS_OTHER if ($? != 0);
+            return pandora_get_os($self->{'dbh'}, $output);
+    }
+    
+    # Use nmap by default
+    if (-e $self->{pa_config}->{nmap}) {
+        my $output = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL | grep 'Aggressive OS guesses'`;
+        return OS_OTHER if ($? != 0);
+        return pandora_get_os($self->{'dbh'}, $output);
+    }
 
-	return OS_OTHER;
+    return OS_OTHER;
 }
 
 ##############################################################################
 # Returns the number of open ports from the given list.
 ##############################################################################
 sub PandoraFMS::Recon::Base::tcp_scan ($$) {
-	my ($self, $host) = @_;
+    my ($self, $host) = @_;
 
-	my $open_ports = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host | grep open | wc -l`;
-	return $open_ports;
+    my $open_ports = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host | grep open | wc -l`;
+    return $open_ports;
 }
 
 ##########################################################################
 # Create network profile modules for the given agent.
 ##########################################################################
 sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) {
-	my ($self, $agent_id, $device) = @_;
-	
-	return unless ($self->{'id_network_profile'} > 0);
-	
-	# Get network components associated to the network profile.
-	my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'});
-	foreach my $np_component (@np_components) {
+    my ($self, $agent_id, $device) = @_;
+    
+    return unless ($self->{'id_network_profile'} > 0);
+    
+    # Get network components associated to the network profile.
+    my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'});
+    foreach my $np_component (@np_components) {
 
-		# Get network component data
-		my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'});
-		if (!defined ($component)) {
-			$self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5);
-			next;
-		}
+        # Get network component data
+        my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'});
+        if (!defined ($component)) {
+            $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5);
+            next;
+        }
 
-		# Use snmp_community from network task instead the component snmp_community
-		$component->{'snmp_community'} = safe_output($self->get_community($device));
-		$component->{'tcp_send'} = $self->{'snmp_version'};
-		$component->{'custom_string_1'} = $self->{'snmp_privacy_method'};
-		$component->{'custom_string_2'} = $self->{'snmp_privacy_pass'};
-		$component->{'custom_string_3'} = $self->{'snmp_security_level'};
-		$component->{'plugin_parameter'} = $self->{'snmp_auth_method'};
-		$component->{'plugin_user'} = $self->{'snmp_auth_user'};
-		$component->{'plugin_pass'} = $self->{'snmp_auth_pass'};
+        # Use snmp_community from network task instead the component snmp_community
+        $component->{'snmp_community'} = safe_output($self->get_community($device));
+        $component->{'tcp_send'} = $self->{'snmp_version'};
+        $component->{'custom_string_1'} = $self->{'snmp_privacy_method'};
+        $component->{'custom_string_2'} = $self->{'snmp_privacy_pass'};
+        $component->{'custom_string_3'} = $self->{'snmp_security_level'};
+        $component->{'plugin_parameter'} = $self->{'snmp_auth_method'};
+        $component->{'plugin_user'} = $self->{'snmp_auth_user'};
+        $component->{'plugin_pass'} = $self->{'snmp_auth_pass'};
 
-		pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'});
-	}
+        pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'});
+    }
 }
 
 ##########################################################################
 # Connect the given devices in the Pandora FMS database.
 ##########################################################################
 sub PandoraFMS::Recon::Base::connect_agents($$$$$) {
-	my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_;
+    my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_;
 
-	# Get the agent for the first device.
-	my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1);
-	if (!defined($agent_1)) {
-		$agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1);
-	}
-	return unless defined($agent_1);
+    # Get the agent for the first device.
+    my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1);
+    if (!defined($agent_1)) {
+        $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1);
+    }
+    return unless defined($agent_1);
 
-	# Get the agent for the second device.
-	my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2);
-	if (!defined($agent_2)) {
-		$agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2);
-	}
-	return unless defined($agent_2);
+    # Get the agent for the second device.
+    my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2);
+    if (!defined($agent_2)) {
+        $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2);
+    }
+    return unless defined($agent_2);
 
-	# Use ping modules by default.
-	$if_1 = 'ping' if ($if_1 eq '');
-	$if_2 = 'ping' if ($if_2 eq '');
+    # Use ping modules by default.
+    $if_1 = 'ping' if ($if_1 eq '');
+    $if_2 = 'ping' if ($if_2 eq '');
 
-	# Check whether the modules exists.
-	my $module_name_1 = $if_1 eq 'ping' ? 'ping' : "${if_1}_ifOperStatus";
-	my $module_name_2 = $if_2 eq 'ping' ? 'ping' : "${if_2}_ifOperStatus";
-	my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'});
-	if ($module_id_1 <= 0) {
-		$self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5);
-		return;
-	}
-	my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'});
-	if ($module_id_2 <= 0) {
-		$self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5);
-		return;
-	}
+    # Check whether the modules exists.
+    my $module_name_1 = $if_1 eq 'ping' ? 'ping' : "${if_1}_ifOperStatus";
+    my $module_name_2 = $if_2 eq 'ping' ? 'ping' : "${if_2}_ifOperStatus";
+    my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'});
+    if ($module_id_1 <= 0) {
+        $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5);
+        return;
+    }
+    my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'});
+    if ($module_id_2 <= 0) {
+        $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5);
+        return;
+    }
 
-	# Connect the modules if they are not already connected.
-	my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ?) OR (module_b = ? AND module_a = ?)', $module_id_1, $module_id_2, $module_id_1, $module_id_2);
-	if (! defined($connection_id)) {
-		db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'});
-	}
+    # Connect the modules if they are not already connected.
+    my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ?) OR (module_b = ? AND module_a = ?)', $module_id_1, $module_id_2, $module_id_1, $module_id_2);
+    if (! defined($connection_id)) {
+        db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'});
+    }
 }
 
 
@@ -427,96 +446,96 @@ sub PandoraFMS::Recon::Base::connect_agents($$$$$) {
 # ]
 ##########################################################################
 sub PandoraFMS::Recon::Base::create_agents($$) {
-	my ($self, $data) = @_;
+    my ($self, $data) = @_;
 
-	my $pa_config = $self->{'pa_config'};
-	my $dbh = $self->{'dbh'};
-	my $server_id = $self->{'server_id'};
+    my $pa_config = $self->{'pa_config'};
+    my $dbh = $self->{'dbh'};
+    my $server_id = $self->{'server_id'};
 
-	return undef if (ref($data) ne "ARRAY");
+    return undef if (ref($data) ne "ARRAY");
 
-	foreach my $information (@{$data}) {
-		my $agent = $information->{'agent_data'};
-		my $modules = $information->{'module_data'};
-		my $force_processing = 0;
+    foreach my $information (@{$data}) {
+        my $agent = $information->{'agent_data'};
+        my $modules = $information->{'module_data'};
+        my $force_processing = 0;
 
-		# Search agent
-		my $current_agent = PandoraFMS::Core::locate_agent(
-			$pa_config, $dbh, $agent->{'agent_name'}
-		);
+        # Search agent
+        my $current_agent = PandoraFMS::Core::locate_agent(
+            $pa_config, $dbh, $agent->{'agent_name'}
+        );
 
-		my $parent_id;
-		if (defined($agent->{'parent_agent_name'})) {
-			$parent_id = PandoraFMS::Core::locate_agent(
-				$pa_config, $dbh, $agent->{'parent_agent_name'}
-			);
-			if ($parent_id) {
-				$parent_id = $parent_id->{'id_agente'};
-			}
-		}
+        my $parent_id;
+        if (defined($agent->{'parent_agent_name'})) {
+            $parent_id = PandoraFMS::Core::locate_agent(
+                $pa_config, $dbh, $agent->{'parent_agent_name'}
+            );
+            if ($parent_id) {
+                $parent_id = $parent_id->{'id_agente'};
+            }
+        }
 
-		my $agent_id;
-		my $os_id = get_os_id($dbh, $agent->{'os'});
+        my $agent_id;
+        my $os_id = get_os_id($dbh, $agent->{'os'});
 
-		if ($os_id < 0) {
-			$os_id = get_os_id($dbh, 'Other');
-		}
+        if ($os_id < 0) {
+            $os_id = get_os_id($dbh, 'Other');
+        }
 
-		if (!$current_agent) {
-			# Create agent.
-			$agent_id = pandora_create_agent(
-				$pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
-				$agent->{'address'}, $agent->{'id_group'}, $parent_id,
-				$os_id, $agent->{'description'},
-				$agent->{'interval'}, $dbh, $agent->{'timezone_offset'}
-			);
+        if (!$current_agent) {
+            # Create agent.
+            $agent_id = pandora_create_agent(
+                $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
+                $agent->{'address'}, $agent->{'id_group'}, $parent_id,
+                $os_id, $agent->{'description'},
+                $agent->{'interval'}, $dbh, $agent->{'timezone_offset'}
+            );
 
-			$current_agent = $parent_id = PandoraFMS::Core::locate_agent(
-				$pa_config, $dbh, $agent->{'agent_name'}
-			);
+            $current_agent = $parent_id = PandoraFMS::Core::locate_agent(
+                $pa_config, $dbh, $agent->{'agent_name'}
+            );
 
-			$force_processing = 1;
+            $force_processing = 1;
 
-		} else {
-			$agent_id = $current_agent->{'id_agente'};
-		}
+        } else {
+            $agent_id = $current_agent->{'id_agente'};
+        }
 
-		if (!defined($agent_id)) {
-			return undef;
-		}
+        if (!defined($agent_id)) {
+            return undef;
+        }
 
-		if ($agent->{'address'} ne '') {
-			pandora_add_agent_address(
-				$pa_config, $agent_id, $agent->{'agent_name'},
-				$agent->{'address'}, $dbh
-			);
-		}
+        if ($agent->{'address'} ne '') {
+            pandora_add_agent_address(
+                $pa_config, $agent_id, $agent->{'agent_name'},
+                $agent->{'address'}, $dbh
+            );
+        }
 
-		# Update agent information
-		pandora_update_agent(
-			$pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id,
-			$agent->{'os_version'}, $agent->{'agent_version'},
-			$agent->{'interval'}, $dbh, undef, $parent_id
-		);
+        # Update agent information
+        pandora_update_agent(
+            $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id,
+            $agent->{'os_version'}, $agent->{'agent_version'},
+            $agent->{'interval'}, $dbh, undef, $parent_id
+        );
 
-		# Add modules.
-		if (ref($modules) eq "ARRAY") {
-			foreach my $module (@{$modules}) {
-				# Translate data structure to simulate XML parser return.
-				my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module};
+        # Add modules.
+        if (ref($modules) eq "ARRAY") {
+            foreach my $module (@{$modules}) {
+                # Translate data structure to simulate XML parser return.
+                my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module};
 
-				# Process modules.
-				PandoraFMS::DataServer::process_module_data (
-					$pa_config, \%data_translated,
-					$server_id, $current_agent,
-					$module->{'name'}, $module->{'type'},
-					$agent->{'interval'},
-					strftime ("%Y/%m/%d %H:%M:%S", localtime()),
-					$dbh, $force_processing
-				);
-			}
-		}
-	}
+                # Process modules.
+                PandoraFMS::DataServer::process_module_data (
+                    $pa_config, \%data_translated,
+                    $server_id, $current_agent,
+                    $module->{'name'}, $module->{'type'},
+                    $agent->{'interval'},
+                    strftime ("%Y/%m/%d %H:%M:%S", localtime()),
+                    $dbh, $force_processing
+                );
+            }
+        }
+    }
 
 }
 
@@ -526,433 +545,433 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
 # existing) agent, undef on error.
 ##########################################################################
 sub PandoraFMS::Recon::Base::create_agent($$) {
-	my ($self, $device) = @_;
+    my ($self, $device) = @_;
 
-	my @agents = get_db_rows($self->{'dbh'},
-		'SELECT * FROM taddress, taddress_agent, tagente
-		 WHERE tagente.id_agente = taddress_agent.id_agent
-			AND taddress_agent.id_a = taddress.id_a
-			AND ip = ?', $device
-	);
+    my @agents = get_db_rows($self->{'dbh'},
+        'SELECT * FROM taddress, taddress_agent, tagente
+         WHERE tagente.id_agente = taddress_agent.id_agent
+            AND taddress_agent.id_a = taddress.id_a
+            AND ip = ?', $device
+    );
 
-	# Does the host already exist?
-	my $agent;
-	foreach my $candidate (@agents) {
-	  $agent = {map {$_} %$candidate}; # copy contents, do not use shallow copy
-	  # exclude $device itself, because it handle corner case when target includes NAT
-	  my @registered = map {$_->{ip}} get_db_rows($self->{'dbh'},
-	  	'SELECT ip FROM taddress, taddress_agent, tagente
-	  	 WHERE tagente.id_agente = taddress_agent.id_agent
-	  		AND taddress_agent.id_a = taddress.id_a
-	  		AND tagente.id_agente = ?
-			AND taddress.ip != ?', $agent->{id_agente}, $device
-	  );
-	  foreach my $ip_addr (@registered) {
-		my @matched = grep { $_ =~ /^$ip_addr$/ } $self->get_addresses($device);
-		if (scalar(@matched) == 0) {
-			$agent = undef;
-			last;
-		}
-	  }
-	  last if(defined($agent)); # exit loop if match all ip_addr
-	}
+    # Does the host already exist?
+    my $agent;
+    foreach my $candidate (@agents) {
+      $agent = {map {$_} %$candidate}; # copy contents, do not use shallow copy
+      # exclude $device itself, because it handle corner case when target includes NAT
+      my @registered = map {$_->{ip}} get_db_rows($self->{'dbh'},
+          'SELECT ip FROM taddress, taddress_agent, tagente
+           WHERE tagente.id_agente = taddress_agent.id_agent
+              AND taddress_agent.id_a = taddress.id_a
+              AND tagente.id_agente = ?
+            AND taddress.ip != ?', $agent->{id_agente}, $device
+      );
+      foreach my $ip_addr (@registered) {
+        my @matched = grep { $_ =~ /^$ip_addr$/ } $self->get_addresses($device);
+        if (scalar(@matched) == 0) {
+            $agent = undef;
+            last;
+        }
+      }
+      last if(defined($agent)); # exit loop if match all ip_addr
+    }
 
-	if (!defined($agent)) {
-		$agent = get_agent_from_name($self->{'dbh'}, $device);
-	}
+    if (!defined($agent)) {
+        $agent = get_agent_from_name($self->{'dbh'}, $device);
+    }
 
-	my ($agent_id, $agent_learning);
-	if (!defined($agent)) {
+    my ($agent_id, $agent_learning);
+    if (!defined($agent)) {
 
-		# Resolve hostnames.
-		my $host_name = $self->{'resolve_names'} == 1 ? gethostbyaddr (inet_aton($device), AF_INET) : $device;
-		$host_name = $device unless defined ($host_name);
+        # Resolve hostnames.
+        my $host_name = $self->{'resolve_names'} == 1 ? gethostbyaddr (inet_aton($device), AF_INET) : $device;
+        $host_name = $device unless defined ($host_name);
 
-		# Guess the OS.
-		my $id_os = $self->guess_os($device);
+        # Guess the OS.
+        my $id_os = $self->guess_os($device);
 
-		# Are we filtering hosts by OS?
-		return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'});
+        # Are we filtering hosts by OS?
+        return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'});
 
-		# Are we filtering hosts by TCP port?
-		return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0);
-		my $location = get_geoip_info($self->{'pa_config'}, $device);
-		$agent_id = pandora_create_agent(
-			$self->{'pa_config'}, $self->{'pa_config'}->{'servername'},
-			$host_name, $device, $self->{'group_id'}, 0, $id_os,
-			'', 300, $self->{'dbh'}, undef, $location->{'longitude'},
-			$location->{'latitude'}
-		);
-		return undef unless defined ($agent_id) and ($agent_id > 0);
+        # Are we filtering hosts by TCP port?
+        return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0);
+        my $location = get_geoip_info($self->{'pa_config'}, $device);
+        $agent_id = pandora_create_agent(
+            $self->{'pa_config'}, $self->{'pa_config'}->{'servername'},
+            $host_name, $device, $self->{'group_id'}, 0, $id_os,
+            '', 300, $self->{'dbh'}, undef, $location->{'longitude'},
+            $location->{'latitude'}
+        );
+        return undef unless defined ($agent_id) and ($agent_id > 0);
 
-		# Autoconfigure agent
-		if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) {
-			my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id);
-			# Update agent configuration once, after create agent.
-			enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]);
-		}
-		
-		if (defined($self->{'main_event_id'})) {
-			my $addresses_str = join(',', safe_output($self->get_addresses($device)));
-			pandora_extended_event(
-				$self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'},
-				"[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id."
-			);
+        # Autoconfigure agent
+        if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) {
+            my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id);
+            # Update agent configuration once, after create agent.
+            enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]);
+        }
+        
+        if (defined($self->{'main_event_id'})) {
+            my $addresses_str = join(',', safe_output($self->get_addresses($device)));
+            pandora_extended_event(
+                $self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'},
+                "[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id."
+            );
 
-		}
-		
-		$agent_learning = 1;
+        }
+        
+        $agent_learning = 1;
 
-		# Create network profile modules for the agent
-		$self->create_network_profile_modules($agent_id, $device);
-	}
-	else {
-		$agent_id = $agent->{'id_agente'};
-		$agent_learning = $agent->{'modo'};
-	}
+        # Create network profile modules for the agent
+        $self->create_network_profile_modules($agent_id, $device);
+    }
+    else {
+        $agent_id = $agent->{'id_agente'};
+        $agent_learning = $agent->{'modo'};
+    }
 
-	# Do not create any modules if the agent is not in learning mode.
-	return unless ($agent_learning == 1);
+    # Do not create any modules if the agent is not in learning mode.
+    return unless ($agent_learning == 1);
 
-	# Add found IP addresses to the agent.
-	foreach my $ip_addr ($self->get_addresses($device)) {
-		my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr);
-		$addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0);
-		next unless ($addr_id > 0);
+    # Add found IP addresses to the agent.
+    foreach my $ip_addr ($self->get_addresses($device)) {
+        my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr);
+        $addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0);
+        next unless ($addr_id > 0);
 
-		# Assign the new address to the agent
-		my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id);
-		if ($agent_addr_id <= 0) {
-			db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`)
-						  VALUES (?, ?)', $addr_id, $agent_id);
-		}
-	}
+        # Assign the new address to the agent
+        my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id);
+        if ($agent_addr_id <= 0) {
+            db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`)
+                          VALUES (?, ?)', $addr_id, $agent_id);
+        }
+    }
 
-	# Create a ping module.
-	my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id);
-	if ($module_id <= 0) {
-		my %module = ('id_tipo_modulo' => 6,
-				   'id_modulo' => 2,
-				   'nombre' => "ping",
-				   'descripcion' => '',
-				   'id_agente' => $agent_id,
-				   'ip_target' => $device);
-		pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-	}
+    # Create a ping module.
+    my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id);
+    if ($module_id <= 0) {
+        my %module = ('id_tipo_modulo' => 6,
+                   'id_modulo' => 2,
+                   'nombre' => "ping",
+                   'descripcion' => '',
+                   'id_agente' => $agent_id,
+                   'ip_target' => $device);
+        pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+    }
 
-	# Add interfaces to the agent if it responds to SNMP.
-	return $agent_id unless ($self->is_snmp_discovered($device));
-	my $community = $self->get_community($device);
+    # Add interfaces to the agent if it responds to SNMP.
+    return $agent_id unless ($self->is_snmp_discovered($device));
+    my $community = $self->get_community($device);
 
-	my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX);
-	foreach my $if_index (@output) {
-		next unless ($if_index =~ /^[0-9]+$/);
+    my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX);
+    foreach my $if_index (@output) {
+        next unless ($if_index =~ /^[0-9]+$/);
 
-		# Check the status of the interface.
-		if ($self->{'all_ifaces'} == 0) {
-			my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index");
-			next unless $if_status == 1;
-		}
+        # Check the status of the interface.
+        if ($self->{'all_ifaces'} == 0) {
+            my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index");
+            next unless $if_status == 1;
+        }
 
-		# Fill the module description with the IP and MAC addresses.
-		my $mac = $self->get_if_mac($device, $if_index);
-		my $ip = $self->get_if_ip($device, $if_index);
-		my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : '');
+        # Fill the module description with the IP and MAC addresses.
+        my $mac = $self->get_if_mac($device, $if_index);
+        my $ip = $self->get_if_ip($device, $if_index);
+        my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : '');
 
-		# Get the name of the network interface.
-		my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index");
-		$if_name = "if$if_index" unless defined ($if_name);
-		$if_name =~ s/"//g;
+        # Get the name of the network interface.
+        my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index");
+        $if_name = "if$if_index" unless defined ($if_name);
+        $if_name =~ s/"//g;
 
-		# Check whether the module already exists.
-		my $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
-		next if ($module_id > 0 && !$agent_learning);
-	
-		# Encode problematic characters.
-		$if_name = safe_input($if_name);
-		$if_desc = safe_input($if_desc);
+        # Check whether the module already exists.
+        my $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
+        next if ($module_id > 0 && !$agent_learning);
+    
+        # Encode problematic characters.
+        $if_name = safe_input($if_name);
+        $if_desc = safe_input($if_desc);
 
-		# Interface status module.
-		$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
-		if ($module_id <= 0) {
-			my %module = ('id_tipo_modulo' => 18,
-				'id_modulo' => 2,
-				'nombre' => "${if_name}_ifOperStatus",
-				'descripcion' => $if_desc,
-				'id_agente' => $agent_id,
-				'ip_target' => $device,
-				'tcp_send' => $self->{'snmp_version'},
-				'custom_string_1' => $self->{'snmp_privacy_method'},
-				'custom_string_2' => $self->{'snmp_privacy_pass'},
-				'custom_string_3' => $self->{'snmp_security_level'},
-				'plugin_parameter' => $self->{'snmp_auth_method'},
-				'plugin_user' => $self->{'snmp_auth_user'},
-				'plugin_pass' => $self->{'snmp_auth_pass'},
-				'snmp_community' => $community,
-				'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"
-			);
-			pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-		} else {
-			my %module = (
-				'descripcion' => $if_desc,
-				'ip_target' => $device,
-				'snmp_community' => $community,
-				'tcp_send' => $self->{'snmp_version'},
-				'custom_string_1' => $self->{'snmp_privacy_method'},
-				'custom_string_2' => $self->{'snmp_privacy_pass'},
-				'custom_string_3' => $self->{'snmp_security_level'},
-				'plugin_parameter' => $self->{'snmp_auth_method'},
-				'plugin_user' => $self->{'snmp_auth_user'},
-				'plugin_pass' => $self->{'snmp_auth_pass'},
-				'tcp_send' => $self->{'snmp_version'},
-			);
-			pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
-		}
+        # Interface status module.
+        $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
+        if ($module_id <= 0) {
+            my %module = ('id_tipo_modulo' => 18,
+                'id_modulo' => 2,
+                'nombre' => "${if_name}_ifOperStatus",
+                'descripcion' => $if_desc,
+                'id_agente' => $agent_id,
+                'ip_target' => $device,
+                'tcp_send' => $self->{'snmp_version'},
+                'custom_string_1' => $self->{'snmp_privacy_method'},
+                'custom_string_2' => $self->{'snmp_privacy_pass'},
+                'custom_string_3' => $self->{'snmp_security_level'},
+                'plugin_parameter' => $self->{'snmp_auth_method'},
+                'plugin_user' => $self->{'snmp_auth_user'},
+                'plugin_pass' => $self->{'snmp_auth_pass'},
+                'snmp_community' => $community,
+                'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"
+            );
+            pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+        } else {
+            my %module = (
+                'descripcion' => $if_desc,
+                'ip_target' => $device,
+                'snmp_community' => $community,
+                'tcp_send' => $self->{'snmp_version'},
+                'custom_string_1' => $self->{'snmp_privacy_method'},
+                'custom_string_2' => $self->{'snmp_privacy_pass'},
+                'custom_string_3' => $self->{'snmp_security_level'},
+                'plugin_parameter' => $self->{'snmp_auth_method'},
+                'plugin_user' => $self->{'snmp_auth_user'},
+                'plugin_pass' => $self->{'snmp_auth_pass'},
+                'tcp_send' => $self->{'snmp_version'},
+            );
+            pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+        }
 
-		# Incoming traffic module.
-		my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
-		if (defined($if_hc_in_octets)) {
-			$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCInOctets", $agent_id);
-			if ($module_id <= 0) {
-				my %module = ('id_tipo_modulo' => 16,
-						   'id_modulo' => 2,
-						   'nombre' => "${if_name}_ifHCInOctets",
-						   'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.',
-						   'id_agente' => $agent_id,
-						   'ip_target' => $device,
-						   'tcp_send' => $self->{'snmp_version'},
-						   'custom_string_1' => $self->{'snmp_privacy_method'},
-						   'custom_string_2' => $self->{'snmp_privacy_pass'},
-						   'custom_string_3' => $self->{'snmp_security_level'},
-						   'plugin_parameter' => $self->{'snmp_auth_method'},
-						   'plugin_user' => $self->{'snmp_auth_user'},
-						   'plugin_pass' => $self->{'snmp_auth_pass'},
-						   'snmp_community' => $community,
-						   'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
-				pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-			} else {
-				my %module = (
-					'ip_target' => $device,
-					'snmp_community' => $community,
-					'tcp_send' => $self->{'snmp_version'},
-					'custom_string_1' => $self->{'snmp_privacy_method'},
-					'custom_string_2' => $self->{'snmp_privacy_pass'},
-					'custom_string_3' => $self->{'snmp_security_level'},
-					'plugin_parameter' => $self->{'snmp_auth_method'},
-					'plugin_user' => $self->{'snmp_auth_user'},
-					'plugin_pass' => $self->{'snmp_auth_pass'},
-				);
-				pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
-			}
-		}
-		# ifInOctets
-		elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) {
-			$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifInOctets", $agent_id);
-			if ($module_id <= 0) {
-				my %module = ('id_tipo_modulo' => 16,
-						   'id_modulo' => 2,
-						   'nombre' => "${if_name}_ifInOctets",
-						   'descripcion' => 'The total number of octets received on the interface, including framing characters.',
-						   'id_agente' => $agent_id,
-						   'ip_target' => $device,
-						   'tcp_send' => $self->{'snmp_version'},
-						   'custom_string_1' => $self->{'snmp_privacy_method'},
-						   'custom_string_2' => $self->{'snmp_privacy_pass'},
-						   'custom_string_3' => $self->{'snmp_security_level'},
-						   'plugin_parameter' => $self->{'snmp_auth_method'},
-						   'plugin_user' => $self->{'snmp_auth_user'},
-						   'plugin_pass' => $self->{'snmp_auth_pass'},
-						   'snmp_community' => $community,
-						   'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index");
-				pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-			} else {
-				my %module = (
-					'ip_target' => $device,
-					'snmp_community' => $community,
-					'tcp_send' => $self->{'snmp_version'},
-					'custom_string_1' => $self->{'snmp_privacy_method'},
-					'custom_string_2' => $self->{'snmp_privacy_pass'},
-					'custom_string_3' => $self->{'snmp_security_level'},
-					'plugin_parameter' => $self->{'snmp_auth_method'},
-					'plugin_user' => $self->{'snmp_auth_user'},
-					'plugin_pass' => $self->{'snmp_auth_pass'},
-				);
-				pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
-			}
-		}
+        # Incoming traffic module.
+        my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
+        if (defined($if_hc_in_octets)) {
+            $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCInOctets", $agent_id);
+            if ($module_id <= 0) {
+                my %module = ('id_tipo_modulo' => 16,
+                           'id_modulo' => 2,
+                           'nombre' => "${if_name}_ifHCInOctets",
+                           'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.',
+                           'id_agente' => $agent_id,
+                           'ip_target' => $device,
+                           'tcp_send' => $self->{'snmp_version'},
+                           'custom_string_1' => $self->{'snmp_privacy_method'},
+                           'custom_string_2' => $self->{'snmp_privacy_pass'},
+                           'custom_string_3' => $self->{'snmp_security_level'},
+                           'plugin_parameter' => $self->{'snmp_auth_method'},
+                           'plugin_user' => $self->{'snmp_auth_user'},
+                           'plugin_pass' => $self->{'snmp_auth_pass'},
+                           'snmp_community' => $community,
+                           'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
+                pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+            } else {
+                my %module = (
+                    'ip_target' => $device,
+                    'snmp_community' => $community,
+                    'tcp_send' => $self->{'snmp_version'},
+                    'custom_string_1' => $self->{'snmp_privacy_method'},
+                    'custom_string_2' => $self->{'snmp_privacy_pass'},
+                    'custom_string_3' => $self->{'snmp_security_level'},
+                    'plugin_parameter' => $self->{'snmp_auth_method'},
+                    'plugin_user' => $self->{'snmp_auth_user'},
+                    'plugin_pass' => $self->{'snmp_auth_pass'},
+                );
+                pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+            }
+        }
+        # ifInOctets
+        elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) {
+            $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifInOctets", $agent_id);
+            if ($module_id <= 0) {
+                my %module = ('id_tipo_modulo' => 16,
+                           'id_modulo' => 2,
+                           'nombre' => "${if_name}_ifInOctets",
+                           'descripcion' => 'The total number of octets received on the interface, including framing characters.',
+                           'id_agente' => $agent_id,
+                           'ip_target' => $device,
+                           'tcp_send' => $self->{'snmp_version'},
+                           'custom_string_1' => $self->{'snmp_privacy_method'},
+                           'custom_string_2' => $self->{'snmp_privacy_pass'},
+                           'custom_string_3' => $self->{'snmp_security_level'},
+                           'plugin_parameter' => $self->{'snmp_auth_method'},
+                           'plugin_user' => $self->{'snmp_auth_user'},
+                           'plugin_pass' => $self->{'snmp_auth_pass'},
+                           'snmp_community' => $community,
+                           'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index");
+                pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+            } else {
+                my %module = (
+                    'ip_target' => $device,
+                    'snmp_community' => $community,
+                    'tcp_send' => $self->{'snmp_version'},
+                    'custom_string_1' => $self->{'snmp_privacy_method'},
+                    'custom_string_2' => $self->{'snmp_privacy_pass'},
+                    'custom_string_3' => $self->{'snmp_security_level'},
+                    'plugin_parameter' => $self->{'snmp_auth_method'},
+                    'plugin_user' => $self->{'snmp_auth_user'},
+                    'plugin_pass' => $self->{'snmp_auth_pass'},
+                );
+                pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+            }
+        }
 
-		# Outgoing traffic module.
-		my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
-		if (defined($if_hc_out_octets)) {
-			$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCOutOctets", $agent_id);
-			if ($module_id <= 0) {
-				my %module = ('id_tipo_modulo' => 16,
-						   'id_modulo' => 2,
-						   'nombre' => "${if_name}_ifHCOutOctets",
-						   'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.',
-						   'id_agente' => $agent_id,
-						   'ip_target' => $device,
-						   'tcp_send' => $self->{'snmp_version'},
-						   'custom_string_1' => $self->{'snmp_privacy_method'},
-						   'custom_string_2' => $self->{'snmp_privacy_pass'},
-						   'custom_string_3' => $self->{'snmp_security_level'},
-						   'plugin_parameter' => $self->{'snmp_auth_method'},
-						   'plugin_user' => $self->{'snmp_auth_user'},
-						   'plugin_pass' => $self->{'snmp_auth_pass'},
-						   'snmp_community' => $community,
-						   'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
-				pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-			} else {
-				my %module = (
-					'ip_target' => $device,
-					'snmp_community' => $community,
-					'tcp_send' => $self->{'snmp_version'},
-					'tcp_send' => $self->{'snmp_version'},
-					'custom_string_1' => $self->{'snmp_privacy_method'},
-					'custom_string_2' => $self->{'snmp_privacy_pass'},
-					'custom_string_3' => $self->{'snmp_security_level'},
-					'plugin_parameter' => $self->{'snmp_auth_method'},
-					'plugin_user' => $self->{'snmp_auth_user'},
-					'plugin_pass' => $self->{'snmp_auth_pass'},
-				);
-				pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
-			}
-		}
-		# ifOutOctets
-		elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) {
-			$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id);
-			if ($module_id <= 0) {
-				my %module = ('id_tipo_modulo' => 16,
-						   'id_modulo' => 2,
-						   'nombre' => "${if_name}_ifOutOctets",
-						   'descripcion' => 'The total number of octets received on the interface, including framing characters.',
-						   'id_agente' => $agent_id,
-						   'ip_target' => $device,
-						   'tcp_send' => $self->{'snmp_version'},
-						   'custom_string_1' => $self->{'snmp_privacy_method'},
-						   'custom_string_2' => $self->{'snmp_privacy_pass'},
-						   'custom_string_3' => $self->{'snmp_security_level'},
-						   'plugin_parameter' => $self->{'snmp_auth_method'},
-						   'plugin_user' => $self->{'snmp_auth_user'},
-						   'plugin_pass' => $self->{'snmp_auth_pass'},
-						   'snmp_community' => $community,
-						   'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index");
-				pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
-			} else {
-				my %module = (
-					'ip_target' => $device,
-					'snmp_community' => $community,
-					'tcp_send' => $self->{'snmp_version'},
-					'tcp_send' => $self->{'snmp_version'},
-					'custom_string_1' => $self->{'snmp_privacy_method'},
-					'custom_string_2' => $self->{'snmp_privacy_pass'},
-					'custom_string_3' => $self->{'snmp_security_level'},
-					'plugin_parameter' => $self->{'snmp_auth_method'},
-					'plugin_user' => $self->{'snmp_auth_user'},
-					'plugin_pass' => $self->{'snmp_auth_pass'},
-				);
-				pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
-			}
-		}
-	}
+        # Outgoing traffic module.
+        my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
+        if (defined($if_hc_out_octets)) {
+            $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCOutOctets", $agent_id);
+            if ($module_id <= 0) {
+                my %module = ('id_tipo_modulo' => 16,
+                           'id_modulo' => 2,
+                           'nombre' => "${if_name}_ifHCOutOctets",
+                           'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.',
+                           'id_agente' => $agent_id,
+                           'ip_target' => $device,
+                           'tcp_send' => $self->{'snmp_version'},
+                           'custom_string_1' => $self->{'snmp_privacy_method'},
+                           'custom_string_2' => $self->{'snmp_privacy_pass'},
+                           'custom_string_3' => $self->{'snmp_security_level'},
+                           'plugin_parameter' => $self->{'snmp_auth_method'},
+                           'plugin_user' => $self->{'snmp_auth_user'},
+                           'plugin_pass' => $self->{'snmp_auth_pass'},
+                           'snmp_community' => $community,
+                           'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
+                pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+            } else {
+                my %module = (
+                    'ip_target' => $device,
+                    'snmp_community' => $community,
+                    'tcp_send' => $self->{'snmp_version'},
+                    'tcp_send' => $self->{'snmp_version'},
+                    'custom_string_1' => $self->{'snmp_privacy_method'},
+                    'custom_string_2' => $self->{'snmp_privacy_pass'},
+                    'custom_string_3' => $self->{'snmp_security_level'},
+                    'plugin_parameter' => $self->{'snmp_auth_method'},
+                    'plugin_user' => $self->{'snmp_auth_user'},
+                    'plugin_pass' => $self->{'snmp_auth_pass'},
+                );
+                pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+            }
+        }
+        # ifOutOctets
+        elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) {
+            $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id);
+            if ($module_id <= 0) {
+                my %module = ('id_tipo_modulo' => 16,
+                           'id_modulo' => 2,
+                           'nombre' => "${if_name}_ifOutOctets",
+                           'descripcion' => 'The total number of octets received on the interface, including framing characters.',
+                           'id_agente' => $agent_id,
+                           'ip_target' => $device,
+                           'tcp_send' => $self->{'snmp_version'},
+                           'custom_string_1' => $self->{'snmp_privacy_method'},
+                           'custom_string_2' => $self->{'snmp_privacy_pass'},
+                           'custom_string_3' => $self->{'snmp_security_level'},
+                           'plugin_parameter' => $self->{'snmp_auth_method'},
+                           'plugin_user' => $self->{'snmp_auth_user'},
+                           'plugin_pass' => $self->{'snmp_auth_pass'},
+                           'snmp_community' => $community,
+                           'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index");
+                pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+            } else {
+                my %module = (
+                    'ip_target' => $device,
+                    'snmp_community' => $community,
+                    'tcp_send' => $self->{'snmp_version'},
+                    'tcp_send' => $self->{'snmp_version'},
+                    'custom_string_1' => $self->{'snmp_privacy_method'},
+                    'custom_string_2' => $self->{'snmp_privacy_pass'},
+                    'custom_string_3' => $self->{'snmp_security_level'},
+                    'plugin_parameter' => $self->{'snmp_auth_method'},
+                    'plugin_user' => $self->{'snmp_auth_user'},
+                    'plugin_pass' => $self->{'snmp_auth_pass'},
+                );
+                pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+            }
+        }
+    }
 
-	return $agent_id;
+    return $agent_id;
 }
 
 ##########################################################################
 # Delete already existing connections.
 ##########################################################################
 sub PandoraFMS::Recon::Base::delete_connections($) {
-	my ($self) = @_;
+    my ($self) = @_;
 
-	$self->call('message', "Deleting connections...", 10);
-	db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'});
+    $self->call('message', "Deleting connections...", 10);
+    db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'});
 }
 
 #######################################################################
 # Print log messages.
 #######################################################################
 sub PandoraFMS::Recon::Base::message($$$) {
-	my ($self, $message, $verbosity) = @_;
-	
-	logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity);
+    my ($self, $message, $verbosity) = @_;
+
+    logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity);
 }
 
 ##########################################################################
 # Connect the given hosts to its parent.
 ##########################################################################
 sub PandoraFMS::Recon::Base::set_parent($$$) {
-	my ($self, $host, $parent) = @_;
+    my ($self, $host, $parent) = @_;
 
-	return unless ($self->{'parent_detection'} == 1);
+    return unless ($self->{'parent_detection'} == 1);
 
-	# Get the agent for the host.
-	my $agent = get_agent_from_addr($self->{'dbh'}, $host);
-	if (!defined($agent)) {
-		$agent = get_agent_from_name($self->{'dbh'}, $host);
-	}
-	return unless defined($agent);
+    # Get the agent for the host.
+    my $agent = get_agent_from_addr($self->{'dbh'}, $host);
+    if (!defined($agent)) {
+        $agent = get_agent_from_name($self->{'dbh'}, $host);
+    }
+    return unless defined($agent);
 
-	# Check if the parent agent exists.
-	my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent);
-	if (!defined($agent_parent)) {
-		$agent_parent = get_agent_from_name($self->{'dbh'}, $parent);
-	}
-	return unless (defined ($agent_parent));
+    # Check if the parent agent exists.
+    my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent);
+    if (!defined($agent_parent)) {
+        $agent_parent = get_agent_from_name($self->{'dbh'}, $parent);
+    }
+    return unless (defined ($agent_parent));
 
-	# Is the agent in learning mode?
-	return unless ($agent_parent->{'modo'} == 1);
+    # Is the agent in learning mode?
+    return unless ($agent_parent->{'modo'} == 1);
 
-	# Connect the host to its parent.
-	db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'});
+    # Connect the host to its parent.
+    db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'});
 }
 
 ##########################################################################
 # Create a WMI module for the given agent.
 ##########################################################################
 sub PandoraFMS::Recon::Base::wmi_module {
-	my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column,
+    my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column,
         $module_name, $module_description, $module_type, $unit) = @_;
 
-	# Check whether the module already exists.
-	my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id);
-	return if ($module_id > 0);
+    # Check whether the module already exists.
+    my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id);
+    return if ($module_id > 0);
 
-	my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef);
-	my %module = (
-		'descripcion' => safe_input($module_description),
-		'id_agente' => $agent_id,
-		'id_modulo' => 6,
-		'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type),
-		'ip_target' => $target,
-		'nombre' => safe_input($module_name),
-		'plugin_pass' => defined($pass) ? $pass : '',
-		'plugin_user' => defined($user) ? $user : '',
-		'snmp_oid' => $wmi_query,
-		'tcp_port' => $column,
-		'unit' => defined($unit) ? $unit : ''
-	);
-	
-	pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'});
+    my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef);
+    my %module = (
+        'descripcion' => safe_input($module_description),
+        'id_agente' => $agent_id,
+        'id_modulo' => 6,
+        'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type),
+        'ip_target' => $target,
+        'nombre' => safe_input($module_name),
+        'plugin_pass' => defined($pass) ? $pass : '',
+        'plugin_user' => defined($user) ? $user : '',
+        'snmp_oid' => $wmi_query,
+        'tcp_port' => $column,
+        'unit' => defined($unit) ? $unit : ''
+    );
+    
+    pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'});
 }
 
 ##########################################################################
 # Update recon task status.
 ##########################################################################
 sub PandoraFMS::Recon::Base::update_progress ($$) {
-	my ($self, $progress) = @_;
+    my ($self, $progress) = @_;
 
-	my $stats = {};
-	if (defined($self->{'summary'}) && $self->{'summary'} ne '') {
-		$stats->{'summary'} = $self->{'summary'};
-	}
-	$stats->{'step'} = $self->{'step'};
-	$stats->{'c_network_name'} = $self->{'c_network_name'};
-	$stats->{'c_network_percent'} = $self->{'c_network_percent'};
+    my $stats = {};
+    if (defined($self->{'summary'}) && $self->{'summary'} ne '') {
+        $stats->{'summary'} = $self->{'summary'};
+    }
+    $stats->{'step'} = $self->{'step'};
+    $stats->{'c_network_name'} = $self->{'c_network_name'};
+    $stats->{'c_network_percent'} = $self->{'c_network_percent'};
 
-	# Store progress, last contact and overall status.
-	db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?',
-		time (), $progress, encode_json($stats), $self->{'task_id'});
+    # Store progress, last contact and overall status.
+    db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?',
+        time (), $progress, encode_json($stats), $self->{'task_id'});
 }
 
 1;
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index afc677c15a..58e0eb8543 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -29,7 +29,9 @@ use constant {
 	DISCOVERY_CLOUD_AWS => 2,
 	DISCOVERY_APP_VMWARE => 3,
 	DISCOVERY_APP_MYSQL => 4,
-	DISCOVERY_APP_ORACLE => 5
+	DISCOVERY_APP_ORACLE => 5,
+	DISCOVERY_CLOUD_AWS_EC2 => 6,
+	DISCOVERY_CLOUD_AWS_RDS => 7
 };
 
 # /dev/null
@@ -1426,6 +1428,54 @@ sub scan_subnet($) {
 	}
 }
 
+
+##########################################################################
+# Perform a Cloud scan
+##########################################################################
+sub cloud_scan($) {
+	my $self = shift;
+	my ($progress, $step);
+
+	my $type = '';
+
+	if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2
+	|| $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+		$type = 'Aws';
+	} else {
+		# Unrecognized task type.
+		call('message', 'Unrecognized task type', 1);
+		$self->call('update_progress', -1);
+		return;
+	}
+
+	# Initialize cloud object.
+	my $cloudObj = PandoraFMS::Recon::Util::enterprise_new(
+		'PandoraFMS::Recon::Cloud::'.$type,
+		[
+			task_data => $self->{'task_data'},
+			aws_access_key_id => $self->{'aws_access_key_id'},
+			aws_secret_access_key => $self->{'aws_secret_access_key'},
+			cloud_util_path => $self->{'cloud_util_path'},
+			parent => $self
+		]
+
+	);
+
+	if (!$cloudObj) {
+		# Failed to initialize, check Cloud credentials or anything.
+		call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3);
+	} else {
+		# Let Cloud object manage scan.
+		$cloudObj->scan();
+	}
+
+	# Update progress.
+	# Done!
+	$self->{'step'} = '';
+	$self->call('update_progress', -1);
+}
+
+
 ##########################################################################
 # Perform an Application scan.
 ##########################################################################
@@ -1597,6 +1647,11 @@ sub scan($) {
 			# Database scan.
 			return $self->app_scan();
 		}
+
+		if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+			# Cloud scan.
+			return $self->cloud_scan();
+		}
 	}
 
 	# Find devices.

From 2af9cbb7119e21b85603326a4952e6e2743c2720 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Wed, 10 Apr 2019 23:16:18 +0200
Subject: [PATCH 23/31] Discovery RDS Bypass perl thread ENV limitation

Former-commit-id: 34ca5374e66c174887683077ba5efcae5412b9bb
---
 .../lib/PandoraFMS/DiscoveryServer.pm         | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 681355011a..cb4ee3dbad 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -108,10 +108,15 @@ sub new ($$$$$$) {
 sub run ($) {
     my $self = shift;
     my $pa_config = $self->getConfig ();
+    my $dbh = $self->getDBH();
     
     print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1);
     my $threads = $pa_config->{'recon_threads'};
 
+    # Prepare some environmental variables.
+    $ENV{'AWS_ACCESS_KEY_ID'} = pandora_get_config_value($dbh, 'aws_access_key_id');
+    $ENV{'AWS_SECRET_ACCESS_KEY'} = pandora_get_config_value($dbh, 'aws_secret_access_key');
+
     # Use hightest value
     if ($pa_config->{'discovery_threads'}  > $pa_config->{'recon_threads'}) {
         $threads = $pa_config->{'discovery_threads'};
@@ -191,6 +196,40 @@ sub data_consumer ($$) {
             $cnf_extra{'aws_access_key_id'} = pandora_get_config_value($dbh, 'aws_access_key_id');
             $cnf_extra{'aws_secret_access_key'} = pandora_get_config_value($dbh, 'aws_secret_access_key');
             $cnf_extra{'cloud_util_path'} = pandora_get_config_value($dbh, 'cloud_util_path');
+
+            if (!defined($ENV{'AWS_ACCESS_KEY_ID'}) || !defined($ENV{'AWS_SECRET_ACCESS_KEY'})
+            || $cnf_extra{'aws_secret_access_key'} ne $ENV{'AWS_ACCESS_KEY_ID'}
+            || $cnf_extra{'cloud_util_path'} ne $ENV{'AWS_SECRET_ACCESS_KEY'}) {
+                # Environmental data is out of date. Create a tmp file to manage
+                # credentials. Perl limitation. We cannot update ENV here.
+                $cnf_extra{'cred_file'} = $pa_config->{'temporal'} . '/tmp_discovery.' . md5($task->{'id_rt'} . $task->{'name'} . time());
+                eval {
+                    open(my $__file_cfg, '> '. $cnf_extra{'cred_file'}) or die($!);
+                    print $__file_cfg $cnf_extra{'aws_secret_access_key'} . "\n";
+                    print $__file_cfg $cnf_extra{'cloud_util_path'};
+                    close($__file_cfg);
+                    set_file_permissions(
+                        $pa_config,
+                        $cnf_extra{'cred_file'},
+                        0600
+                    );
+                };
+                if ($@) {
+                    logger(
+                        $pa_config,
+                        'Cannot instantiate configuration file for task: ' . safe_output($task->{'name'}),
+                        5
+                    );
+                    # A server restart will override ENV definition (see run)
+                    logger(
+                        $pa_config,
+                        'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . '. Please restart the server.',
+                        1
+                    );
+                    # Skip this task.
+                    return;
+                }
+            }
         }
 
         my $recon = new PandoraFMS::Recon::Base(
@@ -229,6 +268,12 @@ sub data_consumer ($$) {
         );
 
         $recon->scan();
+
+        # Clean tmp file.
+        if (defined($cnf_extra{'cred_file'})
+        && -f $cnf_extra{'cred_file'}) {
+			unlink($cnf_extra{'cred_file'});
+		}
     };
     if ($@) {
         update_recon_task ($dbh, $task_id, -1);

From e998c8dd7016334b81bab7e907050aaa7ffa0915 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 11 Apr 2019 15:05:03 +0200
Subject: [PATCH 24/31] Discovery RDS

Former-commit-id: e03d600b06fec25fb5808b9425cc94832d9d1268
---
 .../include/functions_snmp_browser.php           | 16 +++++++++++++---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm |  4 ++--
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/pandora_console/include/functions_snmp_browser.php b/pandora_console/include/functions_snmp_browser.php
index d22dd5dc1e..496a7b747f 100644
--- a/pandora_console/include/functions_snmp_browser.php
+++ b/pandora_console/include/functions_snmp_browser.php
@@ -55,7 +55,9 @@ function snmp_browser_print_tree(
     $last_array=[],
     $sufix=false,
     $checked=[],
-    $return=false
+    $return=false,
+    $descriptive_ids=false,
+    $previous_id=''
 ) {
     static $url = false;
 
@@ -138,7 +140,13 @@ function snmp_browser_print_tree(
         }
 
         $checkbox_name_sufix = ($sufix === true) ? '_'.$level : '';
-        $checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
+        if ($descriptive_ids === true) {
+            $checkbox_name = 'create_'.$sub_id.$previous_id.$checkbox_name_sufix;
+        } else {
+            $checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
+        }
+
+        $previous_id = $checkbox_name_sufix;
         $status = (!empty($checked) && isset($checked[$level]));
         $output .= html_print_checkbox($checkbox_name, 0, $status, true, false, '').'&nbsp;<span>'.$level.'</span>';
         if (isset($sub_level['__VALUE__'])) {
@@ -156,7 +164,9 @@ function snmp_browser_print_tree(
             $last_array,
             $sufix,
             $checked,
-            $return
+            $return,
+            $descriptive_ids,
+            $previous_id
         );
 
         $count++;
diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index cb4ee3dbad..76a8ac766c 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -205,13 +205,13 @@ sub data_consumer ($$) {
                 $cnf_extra{'cred_file'} = $pa_config->{'temporal'} . '/tmp_discovery.' . md5($task->{'id_rt'} . $task->{'name'} . time());
                 eval {
                     open(my $__file_cfg, '> '. $cnf_extra{'cred_file'}) or die($!);
+                    print $__file_cfg $cnf_extra{'aws_access_key_id'} . "\n";
                     print $__file_cfg $cnf_extra{'aws_secret_access_key'} . "\n";
-                    print $__file_cfg $cnf_extra{'cloud_util_path'};
                     close($__file_cfg);
                     set_file_permissions(
                         $pa_config,
                         $cnf_extra{'cred_file'},
-                        0600
+                        "0600"
                     );
                 };
                 if ($@) {

From e80649073f84908e1fcfbd0a75338a240dee39ef Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Thu, 11 Apr 2019 15:36:55 +0200
Subject: [PATCH 25/31] Minor fixes

Former-commit-id: 71698d61db59e7f94fb8c770715decb0fe6e5f0f
---
 pandora_server/lib/PandoraFMS/Config.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm
index 57e3aa9483..2021241d4f 100644
--- a/pandora_server/lib/PandoraFMS/Config.pm
+++ b/pandora_server/lib/PandoraFMS/Config.pm
@@ -1200,7 +1200,7 @@ sub pandora_get_tconfig_token ($$$) {
 	my ($dbh, $token, $default_value) = @_;
 	
 	my $token_value = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = ?", $token);
-	if (defined ($token_value)) {
+	if (defined ($token_value) && $token_value ne '') {
 		return safe_output ($token_value);
 	}
 	

From 8bdc980ab0ebf96f4c18ebd4306c75a2b65cb188 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Fri, 12 Apr 2019 23:47:21 +0200
Subject: [PATCH 26/31] minor fix

Former-commit-id: 4222b217953e88da43d0f50d3217a065dbb13332
---
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm | 12 ++++++------
 pandora_server/lib/PandoraFMS/Recon/Base.pm      |  1 +
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 76a8ac766c..c8b40d1848 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -202,15 +202,15 @@ sub data_consumer ($$) {
             || $cnf_extra{'cloud_util_path'} ne $ENV{'AWS_SECRET_ACCESS_KEY'}) {
                 # Environmental data is out of date. Create a tmp file to manage
                 # credentials. Perl limitation. We cannot update ENV here.
-                $cnf_extra{'cred_file'} = $pa_config->{'temporal'} . '/tmp_discovery.' . md5($task->{'id_rt'} . $task->{'name'} . time());
+                $cnf_extra{'creds_file'} = $pa_config->{'temporal'} . '/tmp_discovery.' . md5($task->{'id_rt'} . $task->{'name'} . time());
                 eval {
-                    open(my $__file_cfg, '> '. $cnf_extra{'cred_file'}) or die($!);
+                    open(my $__file_cfg, '> '. $cnf_extra{'creds_file'}) or die($!);
                     print $__file_cfg $cnf_extra{'aws_access_key_id'} . "\n";
                     print $__file_cfg $cnf_extra{'aws_secret_access_key'} . "\n";
                     close($__file_cfg);
                     set_file_permissions(
                         $pa_config,
-                        $cnf_extra{'cred_file'},
+                        $cnf_extra{'creds_file'},
                         "0600"
                     );
                 };
@@ -270,9 +270,9 @@ sub data_consumer ($$) {
         $recon->scan();
 
         # Clean tmp file.
-        if (defined($cnf_extra{'cred_file'})
-        && -f $cnf_extra{'cred_file'}) {
-			unlink($cnf_extra{'cred_file'});
+        if (defined($cnf_extra{'creds_file'})
+        && -f $cnf_extra{'creds_file'}) {
+			unlink($cnf_extra{'creds_file'});
 		}
     };
     if ($@) {
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 58e0eb8543..23532d843b 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -1456,6 +1456,7 @@ sub cloud_scan($) {
 			aws_access_key_id => $self->{'aws_access_key_id'},
 			aws_secret_access_key => $self->{'aws_secret_access_key'},
 			cloud_util_path => $self->{'cloud_util_path'},
+			creds_file => $self->{'creds_file'},
 			parent => $self
 		]
 

From 6648e0268a3633496f4aa83e2129f7ec1981e2b2 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 15 Apr 2019 12:54:22 +0200
Subject: [PATCH 27/31] removed reconview link from menu

Former-commit-id: 41b80e4eaa41617982c91a218aee3902b76e4fde
---
 pandora_console/operation/menu.php | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/pandora_console/operation/menu.php b/pandora_console/operation/menu.php
index e22769cd8a..f52d830d14 100644
--- a/pandora_console/operation/menu.php
+++ b/pandora_console/operation/menu.php
@@ -492,12 +492,6 @@ if (is_array($config['extensions'])) {
         $sub['godmode/agentes/planned_downtime.list']['id'] = 'Scheduled downtime';
     }
 
-    if (check_acl($config['id_user'], 0, 'AW')) {
-        $sub['operation/servers/recon_view']['text'] = __('Recon view');
-        $sub['operation/servers/recon_view']['id'] = 'Recon view';
-        $sub['operation/servers/recon_view']['refr'] = 0;
-    }
-
     foreach ($config['extensions'] as $extension) {
         // If no operation_menu is a godmode extension.
         if ($extension['operation_menu'] == '') {

From 072fec3dd1bb133b59a3fb2136abfe51d4aafb5e Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 15 Apr 2019 13:03:11 +0200
Subject: [PATCH 28/31] removed map link from mysql/oracle/RDS discovery tasks

Former-commit-id: c01ca25dbe4ca16265a6377d80f60f6d603b7664
---
 pandora_console/godmode/wizards/DiscoveryTaskList.class.php | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 20b52c7e36..fbd8bc4fb6 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -549,7 +549,11 @@ class DiscoveryTaskList extends Wizard
                     $data[9] .= '</a>';
                 }
 
-                if ($task['disabled'] != 2 && $task['utimestamp'] > 0) {
+                if ($task['disabled'] != 2 && $task['utimestamp'] > 0
+                    && $task['type'] != DISCOVERY_APP_MYSQL
+                    && $task['type'] != DISCOVERY_APP_ORACLE
+                    && $task['type'] != DISCOVERY_CLOUD_AWS_RDS
+                ) {
                     $data[9] .= '<a href="#" onclick="show_map('.$task['id_rt'].',\''.$task['name'].'\')">';
                     $data[9] .= html_print_image(
                         'images/dynamic_network_icon.png',

From 8978b49a8b102c1eef23ecff5557519d2420dd03 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 22 Apr 2019 09:33:51 +0200
Subject: [PATCH 29/31] minor fix while setting node_radius by default

Former-commit-id: 37b603adc1eb025c84b4e6d298815894be8adcf6
---
 pandora_console/include/class/NetworkMap.class.php | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php
index fd7274b94f..146e4d999f 100644
--- a/pandora_console/include/class/NetworkMap.class.php
+++ b/pandora_console/include/class/NetworkMap.class.php
@@ -2733,6 +2733,10 @@ class NetworkMap
             $output .= "var z_dash = null;\n";
         }
 
+        if (empty($networkmap['filter']['node_radius']) === true) {
+            $networkmap['filter']['node_radius'] = $this->mapOptions['map_filter']['node_radius'];
+        }
+
         $output .= 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n";
         $output .= 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n";
         $output .= 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n";

From 19ec5a0733bcc5d4a818e1ee088828a03b500bf0 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 22 Apr 2019 13:26:17 +0200
Subject: [PATCH 30/31] minor fix

Former-commit-id: 34ebb713083bce476e15483e710f23295cf842cb
---
 pandora_console/godmode/wizards/DiscoveryTaskList.class.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 3f0317ab6a..3d67e91ae4 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -675,7 +675,7 @@ class DiscoveryTaskList extends Wizard
             return 'wiz=ctask';
 
             default:
-                if ($task['id_recon_script'] === null) {
+                if (empty($task['id_recon_script']) === true) {
                     return 'wiz=hd&mode=netscan';
                 } else {
                     return 'wiz=hd&mode=customnetscan';

From f06e81dcc4bdbd79db24807cfee36da32e48bd6c Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 22 Apr 2019 13:49:58 +0200
Subject: [PATCH 31/31] Discovery: Minor update in description and extra
 information in log

Former-commit-id: b24c095a8c75d190ba03ea089a9d680fcccd5b2b
---
 .../godmode/wizards/DiscoveryTaskList.class.php            | 7 ++++++-
 pandora_server/lib/PandoraFMS/DiscoveryServer.pm           | 5 +++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
index 3d67e91ae4..c9d8951e23 100644
--- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
+++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php
@@ -505,9 +505,14 @@ class DiscoveryTaskList extends Wizard
                                 true,
                                 ['title' => __('Discovery NetScan')]
                             ).'&nbsp;&nbsp;';
-                            $data[6] .= network_profiles_get_name(
+                            $str = network_profiles_get_name(
                                 $task['id_network_profile']
                             );
+                            if (!empty($str)) {
+                                $data[6] .= $str;
+                            } else {
+                                $data[6] .= __('Discovery.NetScan');
+                            }
                         break;
                     }
                 } else {
diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index c8b40d1848..c92b56ed0d 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -276,6 +276,11 @@ sub data_consumer ($$) {
 		}
     };
     if ($@) {
+        logger(
+            $pa_config,
+            'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@,
+            10
+        );
         update_recon_task ($dbh, $task_id, -1);
         return;
     }