Changed migration scripts and migration ini path
This commit is contained in:
parent
67df5ee92a
commit
7e20e6b048
|
@ -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_"
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,979 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
__author__ = ["Enrique Martin Garcia", "Alejandro Sanchez Carrion"]
|
||||||
|
__copyright__ = "Copyright 2023, PandoraFMS"
|
||||||
|
__maintainer__ = "Operations department"
|
||||||
|
__status__ = "Production"
|
||||||
|
__version__= '1.0'
|
||||||
|
|
||||||
|
import sys,os
|
||||||
|
lib_dir = os.path.join(os.path.dirname(sys.argv[0]), 'lib')
|
||||||
|
sys.path.insert(0, lib_dir)
|
||||||
|
|
||||||
|
import signal
|
||||||
|
|
||||||
|
# Define a function to handle the SIGTERM signal
|
||||||
|
def sigterm_handler(signum, frame):
|
||||||
|
print("Received SIGTERM signal. Cleaning up...")
|
||||||
|
sys.exit(0)
|
||||||
|
signal.signal(signal.SIGTERM, sigterm_handler)
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import configparser
|
||||||
|
from queue import Queue
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
###############
|
||||||
|
## VARIABLES ##
|
||||||
|
###############
|
||||||
|
|
||||||
|
# Global variables
|
||||||
|
output = {}
|
||||||
|
error_level = 0
|
||||||
|
summary = {}
|
||||||
|
info = ""
|
||||||
|
monitoring_data = []
|
||||||
|
db_targets = []
|
||||||
|
target_agents = []
|
||||||
|
custom_queries = []
|
||||||
|
|
||||||
|
# Parameters default values
|
||||||
|
threads = 1
|
||||||
|
agents_group_id = 10
|
||||||
|
interval = 300
|
||||||
|
user = ""
|
||||||
|
password = ""
|
||||||
|
modules_prefix = ""
|
||||||
|
execute_custom_queries = 1
|
||||||
|
analyze_connections = 1
|
||||||
|
scan_databases = 0
|
||||||
|
agent_per_database = 0
|
||||||
|
db_agent_prefix = ""
|
||||||
|
innodb_stats = 1
|
||||||
|
engine_uptime = 1
|
||||||
|
query_stats = 1
|
||||||
|
cache_stats = 1
|
||||||
|
|
||||||
|
######################
|
||||||
|
## GLOBAL FUNCTIONS ##
|
||||||
|
######################
|
||||||
|
|
||||||
|
####
|
||||||
|
# Parse parameter input
|
||||||
|
###########################################
|
||||||
|
def param_int(param=""):
|
||||||
|
try:
|
||||||
|
return int(param)
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
####
|
||||||
|
# Get module name with prefix
|
||||||
|
###########################################
|
||||||
|
def get_module_name(name=""):
|
||||||
|
global modules_prefix
|
||||||
|
|
||||||
|
return modules_prefix+name
|
||||||
|
|
||||||
|
####
|
||||||
|
# Set error level to value
|
||||||
|
###########################################
|
||||||
|
def set_error_level(value=0):
|
||||||
|
global error_level
|
||||||
|
|
||||||
|
error_level = value
|
||||||
|
|
||||||
|
####
|
||||||
|
# Set fixed value to summary key
|
||||||
|
###########################################
|
||||||
|
def set_summary_value(key="", value=""):
|
||||||
|
global summary
|
||||||
|
|
||||||
|
summary[key] = value
|
||||||
|
|
||||||
|
####
|
||||||
|
# Add value to summary key
|
||||||
|
###########################################
|
||||||
|
def add_summary_value(key="", value=""):
|
||||||
|
global summary
|
||||||
|
|
||||||
|
if key in summary:
|
||||||
|
summary[key] += value
|
||||||
|
else:
|
||||||
|
set_summary_value(key, value)
|
||||||
|
|
||||||
|
####
|
||||||
|
# Set fixed value to info
|
||||||
|
###########################################
|
||||||
|
def set_info_value(data=""):
|
||||||
|
global info
|
||||||
|
|
||||||
|
info = data
|
||||||
|
|
||||||
|
####
|
||||||
|
# Add data to info
|
||||||
|
###########################################
|
||||||
|
def add_info_value(data=""):
|
||||||
|
global info
|
||||||
|
|
||||||
|
info += data
|
||||||
|
|
||||||
|
####
|
||||||
|
# Add a new agent and modules to JSON
|
||||||
|
###########################################
|
||||||
|
def add_monitoring_data(data={}):
|
||||||
|
global monitoring_data
|
||||||
|
|
||||||
|
monitoring_data.append(data)
|
||||||
|
|
||||||
|
####
|
||||||
|
# Print JSON output and exit script
|
||||||
|
###########################################
|
||||||
|
def print_output():
|
||||||
|
global output
|
||||||
|
global error_level
|
||||||
|
global summary
|
||||||
|
global info
|
||||||
|
global monitoring_data
|
||||||
|
|
||||||
|
output={}
|
||||||
|
if summary:
|
||||||
|
output["summary"] = summary
|
||||||
|
|
||||||
|
if info:
|
||||||
|
output["info"] = info
|
||||||
|
|
||||||
|
if monitoring_data:
|
||||||
|
output["monitoring_data"] = monitoring_data
|
||||||
|
|
||||||
|
json_string = json.dumps(output)
|
||||||
|
|
||||||
|
print(json_string)
|
||||||
|
sys.exit(error_level)
|
||||||
|
|
||||||
|
def parse_parameter(config=None, default="", key=""):
|
||||||
|
try:
|
||||||
|
return config.get("CONF", key)
|
||||||
|
except Exception as e:
|
||||||
|
return default
|
||||||
|
|
||||||
|
########################
|
||||||
|
## SPECIFIC FUNCTIONS ##
|
||||||
|
########################
|
||||||
|
|
||||||
|
####
|
||||||
|
# Format uptime to human readable
|
||||||
|
###########################################
|
||||||
|
def format_uptime(seconds):
|
||||||
|
# Calculate the days, hours, minutes, and seconds
|
||||||
|
minutes, seconds = divmod(seconds, 60)
|
||||||
|
hours, minutes = divmod(minutes, 60)
|
||||||
|
days, hours = divmod(hours, 24)
|
||||||
|
|
||||||
|
# Create the formatted string
|
||||||
|
uptime_string = ""
|
||||||
|
if days > 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='<conf_file>', required=True)
|
||||||
|
parser.add_argument('--target_databases', help='Path to target databases file', metavar='<databases_file>', required=True)
|
||||||
|
parser.add_argument('--target_agents', help='Path to target agents file', metavar='<agents_file>', required=False)
|
||||||
|
parser.add_argument('--custom_queries', help='Path to custom queries file', metavar='<custom_queries_file>', 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()
|
|
@ -0,0 +1,2 @@
|
||||||
|
[deps]
|
||||||
|
pymysql
|
|
@ -1151,7 +1151,7 @@ class ManageExtensions extends HTML
|
||||||
|
|
||||||
// 2. If app not migrated yet, check DiscoveryApplicationsMigrateCodes.ini
|
// 2. If app not migrated yet, check DiscoveryApplicationsMigrateCodes.ini
|
||||||
// Path to the INI file
|
// Path to the INI file
|
||||||
$filePath = $this->path.'/DiscoveryApplicationsMigrateCodes.ini';
|
$filePath = $config['homedir'].'/extras/discovery/DiscoveryApplicationsMigrateCodes.ini';
|
||||||
|
|
||||||
// Parse the INI file
|
// Parse the INI file
|
||||||
$migrationCodes = parse_ini_file($filePath, true);
|
$migrationCodes = parse_ini_file($filePath, true);
|
||||||
|
@ -1347,7 +1347,7 @@ class ManageExtensions extends HTML
|
||||||
|
|
||||||
$scriptName = preg_replace('/^pandorafms\.(\w+)$/m', 'migrate.$1.sql', $shortName);
|
$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 {
|
try {
|
||||||
$res = db_process_file($script_path, true);
|
$res = db_process_file($script_path, true);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
Loading…
Reference in New Issue