From 7e20e6b0488b42eb02dd874ad55e9287609504e0 Mon Sep 17 00:00:00 2001 From: Calvo Date: Tue, 3 Oct 2023 12:10:53 +0200 Subject: [PATCH] Changed migration scripts and migration ini path --- .../pandorafms.mysql/discovery_definition.ini | 172 +++ .../discovery/pandorafms.mysql/logo.png | Bin 0 -> 12952 bytes .../pandorafms.mysql/pandora_mysql.py | 979 ++++++++++++++++++ .../pandorafms.mysql/pandora_mysql.req | 2 + .../DiscoveryApplicationsMigrateCodes.ini | 0 .../migration_scripts/migrate.aws.ec2.sql | 0 .../migration_scripts/migrate.aws.rds.sql | 0 .../migration_scripts/migrate.aws.s3.sql | 0 .../migration_scripts/migrate.azure.sql | 0 .../migration_scripts/migrate.db2.sql | 0 .../migration_scripts/migrate.gcp.ce.sql | 0 .../migration_scripts/migrate.mssql.sql | 0 .../migration_scripts/migrate.mysql.sql | 0 .../migration_scripts/migrate.oracle.sql | 0 .../migration_scripts/migrate.sap.deset.sql | 0 .../migration_scripts/migrate.vmware.sql | 0 .../wizards/ManageExtensions.class.php | 4 +- 17 files changed, 1155 insertions(+), 2 deletions(-) create mode 100644 pandora_console/attachment/discovery/pandorafms.mysql/discovery_definition.ini create mode 100644 pandora_console/attachment/discovery/pandorafms.mysql/logo.png create mode 100644 pandora_console/attachment/discovery/pandorafms.mysql/pandora_mysql.py create mode 100644 pandora_console/attachment/discovery/pandorafms.mysql/pandora_mysql.req rename pandora_console/{attachment => extras}/discovery/DiscoveryApplicationsMigrateCodes.ini (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.aws.ec2.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.aws.rds.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.aws.s3.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.azure.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.db2.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.gcp.ce.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.mssql.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.mysql.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.oracle.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.sap.deset.sql (100%) rename pandora_console/{attachment => extras}/discovery/migration_scripts/migrate.vmware.sql (100%) diff --git a/pandora_console/attachment/discovery/pandorafms.mysql/discovery_definition.ini b/pandora_console/attachment/discovery/pandorafms.mysql/discovery_definition.ini new file mode 100644 index 0000000000..7345f5f1d9 --- /dev/null +++ b/pandora_console/attachment/discovery/pandorafms.mysql/discovery_definition.ini @@ -0,0 +1,172 @@ +[discovery_extension_definition] + +short_name = pandorafms.mysql +section = app +name = MySQL +version = "1.0" +description = Monitor MySQL databases + +execution_file[_exec1_] = "bin/pandora_mysql" + +exec[] = "'_exec1_' --conf '_tempfileConf_' --target_databases '_tempfileTargetDatabases_' --target_agents '_tempfileTargetAgents_' --custom_queries '_tempfileCustomQueries_'" + +default_value[_dbstrings_] = "" +default_value[_dbuser_] = "" +default_value[_dbpass_] = "" +default_value[_threads_] = 1 +default_value[_engineAgent_] = "" +default_value[_prefixModuleName_] = "" +default_value[_scanDatabases_] = false +default_value[_agentPerDatabase_] = false +default_value[_prefixAgent_] = "" +default_value[_checkUptime_] = true +default_value[_queryStats_] = true +default_value[_checkConnections_] = true +default_value[_checkInnodb_] = true +default_value[_checkCache_] = true +default_value[_executeCustomQueries_] = true +default_value[_customQueries_] = "# ======================================================================= +# Custom queries definition guide +# ======================================================================= +# Definition example +# check_begin +# target_databases database where should be executed, default (all) +# name custom name chosen by the user +# description custom description chosen by the user +# operation value | full, +# value returns a simple value, +# full returns all rows in a string +# target query to be executed, +# you can use reserved word $__self_dbname to +# reference current analyzed database name +# datatype module datatype, could be: +# generic_data | generic_data_string | +# generic_proc +# min_warning minimum warning +# max_warning maximum warning +# min_critical minimum critical +# max_critical maximum critical +# inverse_warning if set to 1, warning thresholds has inverse meaning +# inverse_critical if set to 1, warning thresholds has inverse meaning +# str_warning string warning +# str_critical string critical +# unit unit to be displayed in module view +# interval module interval +# parent module parent for this module (name) +# check_end + +" + +[config_steps] + +name[1] = MySQL Base +custom_fields[1] = mysql_base +fields_columns[1] = 1 + +name[2] = MySQL Detailed +custom_fields[2] = mysql_detailed +fields_columns[2] = 1 + +[mysql_base] + +macro[1] = _dbstrings_ +name[1] = MySQL target strings +tip[1] = "SERVER:PORT, comma separated or line by line, as many targets as you need. Use # symbol to comment a line." +type[1] = textarea + +macro[2] = _dbuser_ +name[2] = User +type[2] = string + +macro[3] = _dbpass_ +name[3] = Password +type[3] = password + +[mysql_detailed] + +macro[1] = _threads_ +name[1] = Max threads +type[1] = number +mandatory_field[1] = false + +macro[2] = _engineAgent_ +name[2] = Target agent +tip[2] = Defines a target agent where this task will store data detected, if you have defined multiple targets, define a comma separated or line by line list of names here or leave in blank to use server IP address/FQDN. +type[2] = textarea +mandatory_field[2] = false + +macro[3] = _prefixModuleName_ +name[3] = Custom module prefix +tip[3] = Defines a custom prefix to be concatenated before module names generated by this task. +type[3] = string +mandatory_field[3] = false + +macro[4] = _scanDatabases_ +name[4] = Scan databases +type[4] = checkbox + +macro[5] = _agentPerDatabase_ +name[5] = Create agent per database +type[5] = checkbox + +macro[6] = _prefixAgent_ +name[6] = Custom database agent prefix +tip[6] = Defines a custom prefix to be concatenated before database agent names generated by this task. +type[6] = string +show_on_true[6] = _agentPerDatabase_ +mandatory_field[6] = false + +macro[7] = _checkUptime_ +name[7] = Check engine uptime +type[7] = checkbox + +macro[8] = _queryStats_ +name[8] = Retrieve query statistics +type[8] = checkbox + +macro[9] = _checkConnections_ +name[9] = Analyze connections +type[9] = checkbox + +macro[10] = _checkInnodb_ +name[10] = Retrieve InnoDB statistics +type[10] = checkbox + +macro[11] = _checkCache_ +name[11] = Retrieve cache statistics +type[11] = checkbox + +macro[12] = _executeCustomQueries_ +name[12] = Execute custom queries +type[12] = checkbox + +macro[13] = _customQueries_ +name[13] = Custom queries +tip[13] = Define here your custom queries. +type[13] = textarea +show_on_true[13] = _executeCustomQueries_ +mandatory_field[13] = false + +[tempfile_confs] + +file[_tempfileConf_] = "agents_group_id = __taskGroupID__ +interval = __taskInterval__ +user = _dbuser_ +password = _dbpass_ +threads = _threads_ +modules_prefix = _prefixModuleName_ +execute_custom_queries = _executeCustomQueries_ +analyze_connections = _checkConnections_ +scan_databases = _scanDatabases_ +agent_per_database = _agentPerDatabase_ +db_agent_prefix = _prefixAgent_ +innodb_stats = _checkInnodb_ +engine_uptime = _checkUptime_ +query_stats = _queryStats_ +cache_stats = _checkCache_" + +file[_tempfileTargetDatabases_] = "_dbstrings_" + +file[_tempfileTargetAgents_] = "_engineAgent_" + +file[_tempfileCustomQueries_] = "_customQueries_" \ No newline at end of file diff --git a/pandora_console/attachment/discovery/pandorafms.mysql/logo.png b/pandora_console/attachment/discovery/pandorafms.mysql/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b24a84ceea0c3ad8590bc2721ebda93108a0b8f7 GIT binary patch literal 12952 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 0: + uptime_string += f"{days} days " + if hours > 0: + uptime_string += f"{hours} hours " + if minutes > 0: + uptime_string += f"{minutes} minutes " + uptime_string += f"{seconds} seconds" + + return uptime_string + +#### +# Scan engine databases +########################################### +def get_databases_modules(db_object=None): + global interval + global agents_group_id + global modules_prefix + global agent_per_database + global db_agent_prefix + + # Initialize modules + modules = [] + + if db_object: + # Get all databases + databases = db_object.run_query(f"SHOW DATABASES")[0] + + for db in databases: + # Get database name + db_name = db["Database"] + + # Skip core databases. + if db_name == "mysql": + continue + if db_name == "information_schema": + continue + if db_name == "performance_schema": + continue + if db_name == "sys": + continue + + # Add modules + modules.append({ + "name": get_module_name(db_name+" availability"), + "type": "generic_proc", + "data": 1, + "description": "Database available" + }) + + modules.append({ + "name": get_module_name(db_name+" fragmentation ratio"), + "type": "generic_data", + "data": db_object.run_query(f"SELECT AVG(DATA_FREE/(DATA_LENGTH + INDEX_LENGTH)) AS average_fragmentation_ratio FROM information_schema.tables WHERE table_schema = '{db_name}' GROUP BY table_schema", single_value=True)[0], + "unit": "%", + "description": "Database fragmentation" + }) + + modules.append({ + "name": get_module_name(db_name+" size"), + "type": "generic_data", + "data": db_object.run_query(f"SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size FROM information_schema.tables WHERE table_schema = '{db_name}' GROUP BY table_schema", single_value=True)[0], + "unit": "MB", + "description": "Database size" + }) + + modules += db_object.get_custom_queries(db_name) + + # Add a new agent if agent per database and reset modules + if agent_per_database == 1: + add_monitoring_data({ + "agent_data" : { + "agent_name" : db_agent_prefix+db_object.agent+" "+db_name, + "agent_alias" : db_agent_prefix+db_object.agent+" "+db_name, + "os" : db_object.type, + "os_version" : db_object.version, + "interval" : interval, + "id_group" : agents_group_id, + "address" : db_object.host, + "description" : "", + "parent_agent_name" : db_object.agent, + }, + "module_data" : modules + }) + add_summary_value("Total agents", 1) + add_summary_value("Databases agents", 1) + modules = [] + + return modules + +############# +## CLASSES ## +############# + +#### +# Remote database object +########################################### +class RemoteDB: + def __init__(self, target="", agent=""): + self.type = "MySQL" + self.target = target + self.agent = self.get_agent(agent) + self.parse_target() + self.connected = 0 + self.connector = None + + self.connect() + + self.version = self.get_version() + + def connect(self): + global user + global password + + # Try to connect and capture errors + error = "" + try: + connection = pymysql.connect( + host=self.host, + port=self.port, + user=user, + password=password, + connect_timeout=5 + ) + + # Execute a test query + with connection.cursor() as cursor: + cursor.execute("SELECT 1") + result = cursor.fetchone() + if result: + self.connector = connection + self.connected = 1 + else: + error = "Connection failed" + + except pymysql.Error as e: + error = str(e) + + # Add error to info if cna't connect + if self.connector is None: + add_info_value("["+self.target+"]"+error+"\n") + add_summary_value("Targets down", 1) + else: + add_summary_value("Targets up", 1) + + def disconnect(self): + if self.connected == 1: + self.connector.close() + + def run_query(self, query="", single_row=False, single_value=False, db=""): + if self.connected == 1 and query: + try: + with self.connector.cursor() as cursor: + if db: + cursor.execute(f"USE {db}") + + # Execute your query + cursor.execute(query) + + # Get query fields + fields = [field[0] for field in cursor.description] + + if single_row or single_value: + # Fetch first row + row = cursor.fetchone() + + if single_value: + if row: + # Get first field value + result = str(row[0]) + else: + result = "" + + else: + # Read row + row_item = {} + if row: + i = 0 + # Assign each value for each field in row item + for field in fields: + row_item[field] = str(row[i]) + i += 1 + + result = row_item + + else: + # Fetch all rows + row_items = [] + rows = cursor.fetchall() + + # Read each row + for row in rows: + row_item = {} + i = 0 + # Assign each value for each field in row item + for field in fields: + row_item[field] = str(row[i]) + i += 1 + + # Add row item to row items + row_items.append(row_item) + + result = row_items + + # Close cursor and return result + cursor.close() + return result, True, "" + + except pymysql.Error as e: + add_info_value("["+self.target+"]"+str(e)+"\n") + return None, False, str(e) + else: + return None, False, "Not connected to database" + + def get_agent(self, agent=""): + if agent: + return agent + else: + return self.target.split(":")[0] + + def get_version(self): + version = self.run_query(f"SELECT @@VERSION", single_value=True)[0] + if version is None: + version = "Discovery" + return version + + def parse_target(self): + # Default values + self.port = 3306 + + if ":" in self.target: + target = self.target.split(":") + self.host = target[0] + self.port = int(target[1]) + + else: + self.host = self.target + + def get_statistics(self): + global interval + global modules_prefix + global engine_uptime + global query_stats + global analyze_connections + global innodb_stats + global cache_stats + + # Initialize modules + modules = [] + + # Get status values + status = {} + for var in self.run_query(f"SHOW GLOBAL STATUS")[0]: + status[var["Variable_name"]] = var["Value"] + + # Get svariables values + variables = {} + for var in self.run_query(f"SHOW VARIABLES")[0]: + variables[var["Variable_name"]] = var["Value"] + + # Get modules + if engine_uptime == 1: + modules.append({ + "name": get_module_name("restart detection"), + "type": "generic_proc", + "data": 1 if int(status["Uptime"]) < 2 * interval else 0, + "description": f"Running for {format_uptime(int(status['Uptime']))} (value is 0 if restart detected)" + }) + + if query_stats == 1: + modules.append({ + "name": get_module_name("queries"), + "type": "generic_data_inc_abs", + "data": status["Queries"], + "description": "" + }) + + modules.append({ + "name": get_module_name("query rate"), + "type": "generic_data_inc", + "data": status["Queries"], + }) + + modules.append({ + "name": get_module_name("query select"), + "type": "generic_data_inc_abs", + "data": status["Com_select"], + }) + + modules.append({ + "name": get_module_name("query update"), + "type": "generic_data_inc_abs", + "data": status["Com_update"] + }) + + modules.append({ + "name": get_module_name("query delete"), + "type": "generic_data_inc_abs", + "data": status["Com_delete"] + }) + + modules.append({ + "name": get_module_name("query insert"), + "type": "generic_data_inc_abs", + "data": status["Com_insert"] + }) + + if analyze_connections == 1: + modules.append({ + "name": get_module_name("current connections"), + "type": "generic_data", + "data": status["Threads_connected"], + "description": "Current connections to MySQL engine (global)", + "min_warning": int(variables["max_connections"]) * 0.90, + "min_critical": int(variables["max_connections"]) * 0.98 + }) + + modules.append({ + "name": get_module_name("connections ratio"), + "type": "generic_data", + "data": (int(status["Max_used_connections"]) / int(variables["max_connections"])) * 100, + "description": "This metric indicates if you could run out soon of connection slots.", + "unit": "%", + "min_warning": 85, + "min_critical": 90 + }) + + modules.append({ + "name": get_module_name("aborted connections"), + "type": "generic_data_inc_abs", + "data": status["Aborted_connects"], + "description": "This metric indicates if the ammount of aborted connections in the last interval." + }) + + if innodb_stats == 1: + modules.append({ + "name": get_module_name("Innodb buffer pool pages total"), + "type": "generic_data", + "data": status["Innodb_data_written"], + "description": "Total number of pages in the buffer pool (utilization)." + }) + + modules.append({ + "name": get_module_name("Innodb buffer pool read requests"), + "type": "generic_data_inc_abs", + "data": status["Innodb_buffer_pool_read_requests"], + "description": "Reads from innodb buffer pool." + }) + + modules.append({ + "name": get_module_name("Innodb buffer pool write requests"), + "type": "generic_data_inc_abs", + "data": status["Innodb_buffer_pool_write_requests"], + "description": "Writes in innodb buffer pool." + }) + + modules.append({ + "name": get_module_name("Innodb disk reads"), + "type": "generic_data_inc_abs", + "data": status["Innodb_data_reads"], + "description": "Amount of read operations." + }) + + modules.append({ + "name": get_module_name("Innodb disk writes"), + "type": "generic_data_inc_abs", + "data": status["Innodb_data_writes"], + "description": "Amount of write operations." + }) + + modules.append({ + "name": get_module_name("Innodb disk data read"), + "type": "generic_data_inc_abs", + "data": int(status["Innodb_data_read"])/(1024*1024), + "description": "Amount of data read from disk.", + "unit": "MB" + }) + + modules.append({ + "name": get_module_name("Innodb disk data written"), + "type": "generic_data_inc_abs", + "data": int(status["Innodb_data_written"])/(1024*1024), + "description": "Amount of data written to disk.", + "unit": "MB" + }) + + if cache_stats == 1: + modules.append({ + "name": get_module_name("query cache enabled"), + "type": "generic_proc", + "data": 1 if variables["have_query_cache"] == "YES" else 0, + "description": "Query cache enabled." if variables["have_query_cache"] == "YES" else "Query cache not found, check query_cache_type in your my.cnf" + }) + + if variables["have_query_cache"] == "YES": + if int(status["Qcache_hits"]) + int(status["Qcache_inserts"]) + int(status["Qcache_not_cached"]) != 0: + ratio = 100 * int(status["Qcache_hits"]) / int(status["Qcache_inserts"]) + int(status["Qcache_inserts"]) + int(status["Qcache_not_cached"]) + + modules.append({ + "name": get_module_name("query hit ratio"), + "type": "generic_data", + "data": ratio, + "unit": "%" + }) + + return modules + + def get_custom_queries(self, db=""): + global modules_prefix + global execute_custom_queries + global custom_queries + + # Initialize modules + modules = [] + + # Run if enabled execute custom queries + if execute_custom_queries == 1: + + # Run each custom query + for custom_query in custom_queries: + + # Run if target database match + if "all" in custom_query["target_databases"] or len(custom_query["target_databases"]) == 0 or db in custom_query["target_databases"]: + + # Skipt if empty required parameters + if "target" not in custom_query or not custom_query["target"]: + continue + if "name" not in custom_query or not custom_query["name"]: + continue + + # Reset error + error = "" + # Reset result + data = "" + + # Prepare parameters + sql = custom_query["target"] + sql = re.sub(r'\$__self_dbname', db, sql) + + module_name = custom_query["name"] + module_name = re.sub(r'\$__self_dbname', db, module_name) + + desc = custom_query["description"] if "description" in custom_query else "" + datatype = custom_query["datatype"] if "datatype" in custom_query else "generic_data_string" + + # Set single query + if "operation" not in custom_query or not custom_query["operation"]: + single_value=False + elif custom_query["operation"] == "value": + single_value=True + else: + single_value=False + + # Adjust module type if needed + if(single_value == False): + datatype = "generic_data_string" + + # Run query + rows, status, err = self.run_query(sql, single_value=single_value, db=db) + + # Get query data + if rows is not None: + if isinstance(rows, list): + for row in rows: + for key, value in row.items(): + data += str(value) + "|" + # Remove last pipe + data = data[:-1] + data += "\n" + else: + data = rows + + # Adjust data + if data == "" and "string" in datatype: + data = "No output." + + # Verify query status and set description + if status == False: + desc = "Failed to execute query: " + err; + elif desc == "": + desc = "Execution OK" + + modules.append({ + "name": get_module_name(module_name), + "type": datatype, + "data": data, + "description": desc, + "min_critical": custom_query["min_critical"] if "min_critical" in custom_query else "", + "max_critical": custom_query["max_critical"] if "max_critical" in custom_query else "", + "min_warning": custom_query["min_warning"] if "min_warning" in custom_query else "", + "max_warning": custom_query["max_warning"] if "max_warning" in custom_query else "", + "critical_inverse": custom_query["critical_inverse"] if "critical_inverse" in custom_query else "", + "warning_inverse": custom_query["warning_inverse"] if "warning_inverse" in custom_query else "", + "str_warning": custom_query["str_warning"] if "str_warning" in custom_query else "", + "str_critical": custom_query["str_critical"] if "str_critical" in custom_query else "", + "module_interval":custom_query["module_interval"] if "module_interval" in custom_query else "" + }) + + return modules + + def get_modules(self): + # Initialize modules + modules = [] + + # Get statistics modules + modules += self.get_statistics() + # Get custom queries modules + modules += self.get_custom_queries() + + return modules + +############# +## THREADS ## +############# + +#### +# Function per agent +########################################### +def monitor_items(thread_agents=[]): + global target_agents + global interval + global agents_group_id + + for thread_agent in thread_agents: + # Get target agent + agent = "" + if 0 <= thread_agent["id"] < len(target_agents): + agent = target_agents[thread_agent["id"]] + + # Initialize modules + modules=[] + + # Get DB object + db_object = RemoteDB(thread_agent["db_target"], agent) + + # Add connection module + modules.append({ + "name" : get_module_name(db_object.type+" connection"), + "type" : "generic_proc", + "description" : db_object.type+" availability", + "data" : db_object.connected + }) + + # Get global connection modules if connected + if(db_object.connected == 1): + modules += db_object.get_modules() + + # Get engine databases modules + if scan_databases == 1: + modules += get_databases_modules(db_object) + + # Add new monitoring data + add_monitoring_data({ + "agent_data" : { + "agent_name" : db_object.agent, + "agent_alias" : db_object.agent, + "os" : db_object.type, + "os_version" : db_object.version, + "interval" : interval, + "id_group" : agents_group_id, + "address" : db_object.host, + "description" : "", + }, + "module_data" : modules + }) + add_summary_value("Total agents", 1) + add_summary_value("Target agents", 1) + + # Disconnect from target + db_object.disconnect() + + +#### +# Function per thread +########################################### +def monitor_threads(): + global q + + thread_agents=q.get() + try: + monitor_items(thread_agents) + q.task_done() + except Exception as e: + q.task_done() + set_error_level(1) + add_info_value("Error while runing single thread: "+str(e)+"\n") + + +########## +## MAIN ## +########## + +# Parse arguments +parser = argparse.ArgumentParser(description= "", formatter_class=argparse.RawTextHelpFormatter) +parser.add_argument('--conf', help='Path to configuration file', metavar='', required=True) +parser.add_argument('--target_databases', help='Path to target databases file', metavar='', required=True) +parser.add_argument('--target_agents', help='Path to target agents file', metavar='', required=False) +parser.add_argument('--custom_queries', help='Path to custom queries file', metavar='', required=False) +args = parser.parse_args() + +# Parse configuration file +config = configparser.ConfigParser() +try: + config.read_string('[CONF]\n' + open(args.conf).read()) +except Exception as e: + set_error_level(1) + set_info_value("Error while reading configuration file file: "+str(e)+"\n") + print_output() + +agents_group_id = param_int(parse_parameter(config, agents_group_id, "agents_group_id")) +interval = param_int(parse_parameter(config, interval, "interval")) +user = parse_parameter(config, user, "user") +password = parse_parameter(config, password, "password") +threads = param_int(parse_parameter(config, threads, "threads")) +modules_prefix = parse_parameter(config, modules_prefix, "modules_prefix") +execute_custom_queries = param_int(parse_parameter(config, execute_custom_queries, "execute_custom_queries")) +analyze_connections = param_int(parse_parameter(config, analyze_connections, "analyze_connections")) +scan_databases = param_int(parse_parameter(config, scan_databases, "scan_databases")) +agent_per_database = param_int(parse_parameter(config, agent_per_database, "agent_per_database")) +db_agent_prefix = parse_parameter(config, db_agent_prefix, "db_agent_prefix") +innodb_stats = param_int(parse_parameter(config, innodb_stats, "innodb_stats")) +engine_uptime = param_int(parse_parameter(config, engine_uptime, "engine_uptime")) +query_stats = param_int(parse_parameter(config, query_stats, "query_stats")) +cache_stats = param_int(parse_parameter(config, cache_stats, "cache_stats")) + +# Parse rest of files +t_file = args.target_databases +a_file = args.target_agents +cq_file = args.custom_queries + +# Parse DB targets +if t_file: + try: + lines = open(t_file, "r") + for line in lines: + line = line.strip() + # SKIP EMPTY AND COMMENTED LINES + if not line: + continue + if line == "\n": + continue + if line[0] == '#': + continue + + db_targets += [element.strip() for element in line.split(",")] + lines = [] + + except Exception as e: + set_error_level(1) + add_info_value("Error while reading DB targets file: "+str(e)+"\n") + +# Parse target agents +if a_file: + try: + lines = open(a_file, "r") + for line in lines: + line = line.strip() + # SKIP EMPTY AND COMMENTED LINES + if not line: + continue + if line == "\n": + continue + if line[0] == '#': + continue + + target_agents += [element.strip() for element in line.split(",")] + lines = [] + + except Exception as e: + set_error_level(1) + add_info_value("Error while reading target agents file: "+str(e)+"\n") + +# Parse custom queries +if cq_file: + try: + custom_query = {} + save = False + + lines = open(cq_file, "r") + for line in lines: + line = line.strip() + # SKIP EMPTY AND COMMENTED LINES + if not line: + continue + if line == "\n": + continue + if line[0] == '#': + continue + + # Start parsing module + if line == "check_begin": + save = True + continue + + # Read next line until new module + if save == False: + continue + + # End parsing module + if line == "check_end": + if "target_databases" not in custom_query: + custom_query["target_databases"] = ["all"] + custom_queries.append(custom_query) + custom_query = {} + save = False + continue + + # Get line key value pair + key, value = [element.strip() for element in line.split(maxsplit=1)] + + # Add target databases to query + if key == "target_databases": + custom_query["target_databases"] = [element.strip() for element in value.split(",")] + continue + + # Skip not select queries + if key == "target" and not re.search(r'^select', value, re.IGNORECASE): + add_info_value("Removed ["+value+"] from custom queries, only select queries are allowed.\n") + continue + + # Add other parameters to query + custom_query[key] = value + lines = [] + + except Exception as e: + set_error_level(1) + add_info_value("Error while reading custom queries file: "+str(e)+"\n") + +# Verify required arguments +required_params = True +if not user: + add_info_value("Parameter [user] not defined\n") + required_params = False +if not password: + add_info_value("Parameter [password] not defined\n") + required_params = False +if not db_targets: + add_info_value("Database targets not defined\n") + required_params = False + +if required_params == False: + set_error_level(1) + print_output() + +# Initialize summary +set_summary_value("Total agents", 0) +set_summary_value("Target agents", 0) +set_summary_value("Databases agents", 0) +set_summary_value("Targets up", 0) +set_summary_value("Targets down", 0) + +# Assign threads +if threads > len(db_targets): + threads = len(db_targets) + +if threads < 1: + threads = 1 + +# Distribute agents per thread +agents_per_thread = [] +thread = 0 +i = 0 +for db_target in db_targets: + if not 0 <= thread < len(agents_per_thread): + agents_per_thread.append([]) + + agents_per_thread[thread].append({ + "id": i, + "db_target": db_target + }) + + thread += 1 + if thread >= threads: + thread=0 + + i += 1 + +# Run threads +try: + q=Queue() + for n_thread in range(threads) : + q.put(agents_per_thread[n_thread]) + + run_threads = [] + for n_thread in range(threads): + t = Thread(target=monitor_threads) + t.daemon=True + t.start() + run_threads.append(t) + + for t in run_threads: + t.join() + + q.join() + +except Exception as e: + add_info_value("Error while running threads: "+str(e)+"\n") + set_error_level(1) + +# Print output and exit script +print_output() \ No newline at end of file diff --git a/pandora_console/attachment/discovery/pandorafms.mysql/pandora_mysql.req b/pandora_console/attachment/discovery/pandorafms.mysql/pandora_mysql.req new file mode 100644 index 0000000000..057adf64fc --- /dev/null +++ b/pandora_console/attachment/discovery/pandorafms.mysql/pandora_mysql.req @@ -0,0 +1,2 @@ +[deps] +pymysql \ No newline at end of file diff --git a/pandora_console/attachment/discovery/DiscoveryApplicationsMigrateCodes.ini b/pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini similarity index 100% rename from pandora_console/attachment/discovery/DiscoveryApplicationsMigrateCodes.ini rename to pandora_console/extras/discovery/DiscoveryApplicationsMigrateCodes.ini diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.aws.ec2.sql b/pandora_console/extras/discovery/migration_scripts/migrate.aws.ec2.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.aws.ec2.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.aws.ec2.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.aws.rds.sql b/pandora_console/extras/discovery/migration_scripts/migrate.aws.rds.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.aws.rds.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.aws.rds.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.aws.s3.sql b/pandora_console/extras/discovery/migration_scripts/migrate.aws.s3.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.aws.s3.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.aws.s3.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.azure.sql b/pandora_console/extras/discovery/migration_scripts/migrate.azure.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.azure.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.azure.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.db2.sql b/pandora_console/extras/discovery/migration_scripts/migrate.db2.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.db2.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.db2.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.gcp.ce.sql b/pandora_console/extras/discovery/migration_scripts/migrate.gcp.ce.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.gcp.ce.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.gcp.ce.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.mssql.sql b/pandora_console/extras/discovery/migration_scripts/migrate.mssql.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.mssql.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.mssql.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.mysql.sql b/pandora_console/extras/discovery/migration_scripts/migrate.mysql.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.mysql.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.mysql.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.oracle.sql b/pandora_console/extras/discovery/migration_scripts/migrate.oracle.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.oracle.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.oracle.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.sap.deset.sql b/pandora_console/extras/discovery/migration_scripts/migrate.sap.deset.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.sap.deset.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.sap.deset.sql diff --git a/pandora_console/attachment/discovery/migration_scripts/migrate.vmware.sql b/pandora_console/extras/discovery/migration_scripts/migrate.vmware.sql similarity index 100% rename from pandora_console/attachment/discovery/migration_scripts/migrate.vmware.sql rename to pandora_console/extras/discovery/migration_scripts/migrate.vmware.sql diff --git a/pandora_console/godmode/wizards/ManageExtensions.class.php b/pandora_console/godmode/wizards/ManageExtensions.class.php index 94f1a2826b..ffbf5f738a 100644 --- a/pandora_console/godmode/wizards/ManageExtensions.class.php +++ b/pandora_console/godmode/wizards/ManageExtensions.class.php @@ -1151,7 +1151,7 @@ class ManageExtensions extends HTML // 2. If app not migrated yet, check DiscoveryApplicationsMigrateCodes.ini // Path to the INI file - $filePath = $this->path.'/DiscoveryApplicationsMigrateCodes.ini'; + $filePath = $config['homedir'].'/extras/discovery/DiscoveryApplicationsMigrateCodes.ini'; // Parse the INI file $migrationCodes = parse_ini_file($filePath, true); @@ -1347,7 +1347,7 @@ class ManageExtensions extends HTML $scriptName = preg_replace('/^pandorafms\.(\w+)$/m', 'migrate.$1.sql', $shortName); - $script_path = $config['attachment_store'].'/discovery/migration_scripts/'.$scriptName; + $script_path = $config['homedir'].'/extras/discovery/migration_scripts/'.$scriptName; try { $res = db_process_file($script_path, true); } catch (\Exception $e) {