Files
yakpanel-core/class/database.py
2026-04-07 02:04:22 +05:30

1689 lines
84 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2017 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: hwliang <hwl@yakpanel.com>
# -------------------------------------------------------------------
# ------------------------------
# 数据库管理类
# ------------------------------
import os
import time
import json
import re
import sys
import public, db, panelMysql
from YakPanel import session
import datatool
import db_mysql
class database(datatool.datatools):
_MYSQL_CNF = "/etc/my.cnf"
_DB_BACKUP_DIR = os.path.join(public.M("config").where("id=?", (1,)).getField("backup_path"), "database")
_MYSQL_BACKUP_DIR = os.path.join(_DB_BACKUP_DIR, "mysql")
_MYSQLDUMP_BIN = public.get_mysqldump_bin()
_MYSQL_BIN = public.get_mysql_bin()
sqlite_connection = None
def __init__(self):
if not os.path.exists(self._MYSQL_BACKUP_DIR):
os.makedirs(self._MYSQL_BACKUP_DIR)
sid = 0
def AddCloudServer(self, get):
'''
@name 添加远程服务器
@author hwliang<2021-01-10>
@param db_host<string> 服务器地址
@param db_port<port> 数据库端口
@param db_user<string> 用户名
@param db_password<string> 数据库密码
@param db_ps<string> 数据库备注
@return dict
'''
if not hasattr(get, 'db_host'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_port'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_user'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_password'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_ps'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
get.db_name = None
res = self.CheckCloudDatabase(get)
if isinstance(res, dict): return res
if public.M('database_servers').where('db_host=? AND db_port=?', (get.db_host, get.db_port)).count():
return public.return_msg_gettext(False, 'The specified server already exists: [{}:{}]',
(get.db_host, get.db_port))
get.db_port = int(get.db_port)
pdata = {
'db_host': get.db_host,
'db_port': get.db_port,
'db_user': get.db_user,
'db_password': get.db_password,
'ps': public.xssencode2(get.db_ps.strip()),
'addtime': int(time.time())
}
result = public.M("database_servers").insert(pdata)
if isinstance(result, int):
public.write_log_gettext('Database manager', 'Add remote MySQL server [{}:{}]', (get.db_host, get.db_port))
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
return public.return_msg_gettext(False, 'Add failed: {}', (result,))
def GetCloudServer(self, get):
'''
@name 获取远程服务器列表
@author hwliang<2021-01-10>
@return list
'''
data = public.M('database_servers').where("db_type=?", ("mysql",)).select()
bt_mysql_bin = '{}/mysql/bin/mysql'.format(public.get_setup_path())
if not isinstance(data, list): data = []
if os.path.exists(bt_mysql_bin):
data.insert(0, {'id': 0, 'db_host': '127.0.0.1', 'db_port': 3306, 'db_user': 'root', 'db_password': '',
'ps': 'LocalServer', 'addtime': 0})
return data
def RemoveCloudServer(self, get):
'''
@name 删除远程服务器
@author hwliang<2021-01-10>
@param id<int> 远程服务器ID
@return dict
'''
id = int(get.id)
if not id: return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
db_find = public.M('database_servers').where('id=?', (id,)).find()
if not db_find: return public.returnMsg(False, public.lang("The specified server dose not exists!"))
public.M('databases').where('sid=?', id).delete()
result = public.M('database_servers').where('id=?', id).delete()
if isinstance(result, int):
public.WriteLog('Database manager', 'Delete the remote MySQL server [{}:{}]',
(db_find['db_host'], int(db_find['db_port'])))
return public.return_msg_gettext(True, public.lang("Successfully deleted!"))
return public.return_msg_gettext(False, 'Failed to delete: {}', (result,))
def ModifyCloudServer(self, get):
'''
@name 修改远程服务器
@author hwliang<2021-01-10>
@param id<int> 远程服务器ID
@param db_host<string> 服务器地址
@param db_port<port> 数据库端口
@param db_user<string> 用户名
@param db_password<string> 数据库密码
@param db_ps<string> 数据库备注
@return dict
'''
if not hasattr(get, 'id'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_host'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_port'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_user'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_password'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_ps'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
id = int(get.id)
get.db_port = int(get.db_port)
db_find = public.M('database_servers').where('id=?', (id,)).find()
if not db_find: return public.return_msg_gettext(False, public.lang("The specified server dose not exists!"))
_modify = False
if db_find['db_host'] != get.db_host or db_find['db_port'] != get.db_port:
_modify = True
if public.M('database_servers').where('db_host=? AND db_port=?', (get.db_host, get.db_port)).count():
return public.return_msg_gettext(False, 'The specified server already exists: [{}:{}]',
(get.db_host, get.db_port))
if db_find['db_user'] != get.db_user or db_find['db_password'] != get.db_password:
_modify = True
if _modify:
res = self.CheckCloudDatabase(get)
if isinstance(res, dict): return res
pdata = {
'db_host': get.db_host,
'db_port': get.db_port,
'db_user': get.db_user,
'db_password': get.db_password,
'ps': public.xssencode2(get.db_ps.strip())
}
result = public.M("database_servers").where('id=?', (id,)).update(pdata)
if isinstance(result, int):
public.WriteLog('Database manager', 'Edit remote MySQL server [{}:{}]', (get.db_host, get.db_port))
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
return public.return_msg_gettext(False, 'Fail to edit: {}', (result))
def AddCloudDatabase(self, get):
'''
@name 添加远程数据库
@author hwliang<2022-01-06>
@param db_host<string> 服务器地址
@param db_port<port> 数据库端口
@param db_user<string> 用户名
@param db_name<string> 数据库名称
@param db_password<string> 数据库密码
@param db_ps<string> 数据库备注
@return dict
'''
if not hasattr(get, 'db_host'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_port'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_user'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_name'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_password'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
if not hasattr(get, 'db_ps'):
return public.return_msg_gettext(False, public.lang("Parameter ERROR!"))
# 检查数据库是否能连接
res = self.CheckCloudDatabase(get)
if isinstance(res, dict): return res
if public.M('databases').where('name=?', (get.db_name,)).count():
return public.return_msg_gettext(False, "A database with the same name already exists: [{}]",
(get.db_name,))
get.db_port = int(get.db_port)
conn_config = {
'db_host': get.db_host,
'db_port': get.db_port,
'db_user': get.db_user,
'db_password': get.db_password,
'db_name': get.db_name
}
pdata = {
'name': get.db_name,
'ps': get.db_ps,
'conn_config': json.dumps(conn_config),
'db_type': '1',
'username': get.db_user,
'password': get.db_password,
'accept': '127.0.0.1',
'addtime': time.strftime('%Y-%m-%d %X', time.localtime()),
'pid': 0
}
result = public.M('databases').insert(pdata)
if isinstance(result, int):
public.write_log_gettext('Database manager', 'Add remote MySQL database [{}] successfully', (get.db_name,))
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
return public.return_msg_gettext(False, 'Add failed: {}', (result,))
def CheckCloudDatabase(self, conn_config):
'''
@name 检查远程数据库信息是否正确
@author hwliang<2022-01-06>
@param conn_config<dict> 连接信息
db_host<string> 服务器地址
db_port<port> 数据库端口
db_user<string> 用户名
db_name<string> 数据库名称
db_password<string> 数据库密码
@return True / dict
'''
try:
if not 'db_name' in conn_config: conn_config['db_name'] = None
mysql_obj = db_mysql.panelMysql()
mysql_obj.set_host(conn_config['db_host'], conn_config['db_port'], conn_config['db_name'],
conn_config['db_user'], conn_config['db_password'])
result = mysql_obj.query("show databases")
if isinstance(result, str):
if mysql_obj._ex:
return public.returnMsg(False, self.GetMySQLError(mysql_obj._ex))
else:
return public.returnMsg(False, self.GetMySQLError(result))
if not conn_config['db_name']: return True
for i in result:
if i[0] == conn_config['db_name']:
return True
return public.returnMsg(False, public.lang("The specified database does not exist!"))
except Exception as ex:
res = self.GetMySQLError(ex)
if not res: res = str(ex)
return public.returnMsg(False, res)
def GetMySQLError(self, e):
if isinstance(e, str):
return e
res = ''
if e.args[0] == 1045:
res = public.gettext_msg("Wrong user name or password!")
if e.args[0] == 1049:
res = public.gettext_msg("Database does NOT exist!")
if e.args[0] == 1044:
res = public.gettext_msg("No access rights, or the database does not exist!")
if e.args[0] == 1062:
res = public.gettext_msg("Database exists!")
if e.args[0] == 1146:
res = public.gettext_msg('Database table does not exist!')
if e.args[0] == 2003:
res = public.gettext_msg('Fail to connect to the server!')
if res:
res = res + "<pre>" + str(e) + "</pre>"
else:
res = str(e)
return res
# 检查mysql是否存在空用户密码
def _check_empty_user_passwd(self):
mysql_obj = panelMysql.panelMysql()
mysql_obj.execute("delete from mysql.user where user='' and password=''")
# 添加数据库
def AddDatabase(self, get):
self._check_empty_user_passwd()
ssl = ""
if hasattr(get, "ssl"):
ssl = get.ssl
if ssl == "REQUIRE SSL" and not self.check_mysql_ssl_status(get):
return public.return_msg_gettext(False, public.lang("SSL is not enabled in the database, please open it in the Mysql manager first"))
data_name = get['name'].strip().lower()
if not data_name: return public.return_msg_gettext(False, public.lang("The database name cannot be empty"))
if self.CheckRecycleBin(data_name):
return public.return_msg_gettext(False,'Database [{}] already at the recycle bin, please recover from the recycle bin!', (data_name,))
if len(data_name) > 64: return public.return_msg_gettext(False, public.lang("Database name cannot be more than 16 characters!"))
reg = r"^[\w\.-]+$"
username = get.db_user.strip()
if not username: return public.return_msg_gettext(False, public.lang("The database user name cannot be empty"))
if not re.match(reg, data_name): return public.return_msg_gettext(False, public.lang("Database name cannot contain special characters!"))
if not re.match(reg, username): return public.return_msg_gettext(False, public.lang("Database name is illegal!"))
if not hasattr(get, 'db_user'): get.db_user = data_name
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
if username in checks or len(username) < 1: return public.return_msg_gettext(False, public.lang("Database username is illegal!"))
if data_name in checks or len(data_name) < 1: return public.return_msg_gettext(False, public.lang("Database name is illegal!"))
data_pwd = get['password']
if len(data_pwd) < 1:
data_pwd = public.md5(str(time.time()))[0:16]
sql = public.M('databases')
if sql.where("name=?", (data_name)).count(): return public.return_msg_gettext(False, public.lang("Database exists!"))
if sql.where("username=?", (username)).count(): return public.return_msg_gettext(False, public.lang("The user name already exists. For security reasons, we do not allow one database user to manage multiple databases"))
address = get['address'].strip()
if address in ['', 'ip']: return public.return_msg_gettext(False, public.lang("If the access permission is [Specified IP], you need to enter the IP address!"))
password = data_pwd
codeing = get['codeing']
wheres = {
'utf8': 'utf8_general_ci',
'utf8mb4': 'utf8mb4_general_ci',
'gbk': 'gbk_chinese_ci',
'big5': 'big5_chinese_ci'
}
codeStr = wheres[codeing]
# 添加MYSQL
self.sid = get.get('sid/d', 0)
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj:
return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
# 从MySQL验证是否存在
if self.database_exists_for_mysql(mysql_obj, data_name):
return public.return_msg_gettext(False, public.lang("The specified database already exists in MySQL, please change the name!"))
result = mysql_obj.execute(
"create database `" + data_name + "` DEFAULT CHARACTER SET " + codeing + " COLLATE " + codeStr)
isError = self.IsSqlError(result)
if isError is not None:
return isError
mysql_obj.execute("drop user '" + username + "'@'localhost'")
for a in address.split(','):
mysql_obj.execute("drop user '" + username + "'@'" + a + "'")
self.__CreateUsers(data_name, username, password, address, ssl)
if get['ps'] == '': get['ps'] = public.lang("Edit notes")
get['ps'] = public.xssencode2(get['ps'])
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
pid = 0
if hasattr(get, 'pid'): pid = get.pid
# 添加入SQLITE
db_type = 0
if self.sid: db_type = 2
db_id = sql.add('pid,sid,db_type,name,username,password,accept,ps,addtime',
(pid, self.sid, db_type, data_name, username, password, address, get['ps'], addTime))
public.write_log_gettext("Database manager", 'Successfully added database [{}]!', (data_name,))
return {**public.return_message(True, 0, public.lang("Setup successfully!")), "id": db_id}
# 生成mysql证书
def _create_mysql_ssl(self):
ip = public.readFile("/www/server/panel/data/iplist.txt")
openssl_command = """
cd /www/server/data
openssl genrsa 2048 > ca-key.pem
openssl req -sha1 -new -x509 -nodes -subj "/C=CA/ST=CA/L=CA/O=CA/OU=CA/CN={ip}BT" -days 3650 -key ca-key.pem > ca.pem
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -subj "/C=CA/ST=CA/L=CA/O=CA/OU=CA/CN={ip}" -keyout server-key.pem > server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -subj "/C=CA/ST=CA/L=CA/O=CA/OU=CA/CN={ip}" -keyout client-key.pem > client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem
zip -q ssl.zip client-cert.pem client-key.pem ca.pem
""".format(ip=ip)
public.ExecShell(openssl_command)
# 写入mysqlssl到配置
def write_ssl_to_mysql(self, get):
# ssl_conf = """
# ssl-ca=/www/server/data/ca.pem
# ssl-cert=/www/server/data/server-cert.pem
# ssl-key=/www/server/data/server-key.pem
# """
ssl_original_path = """
ssl-ca=/www/server/mysql/mysql-test/std_data/cacert.pem
ssl-cert=/www/server/mysql/mysql-test/std_data//server-cert.pem
ssl-key=/www/server/mysql/mysql-test/std_data/server-key.pem
"""
conf_file = "/etc/my.cnf"
conf = public.readFile(conf_file)
if not conf:
return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
if self.check_mysql_ssl_status(get):
reg = "ssl-ca=/www.*\n.*\n.*server-key.pem\n"
conf = re.sub(reg, "", conf)
if os.path.exists('/www/server/mysql/mysql-test/std_data/server-cert.pem'):
conf = re.sub(r'\[mysqld\]', '[mysqld]\nskip_ssl', conf)
public.writeFile(conf_file, conf)
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
# create_ssl = None
# for i in ['5.5','5.6','10.1','10.2','10.3']:
# if i not in public.readFile('/www/server/mysql/version_check.pl'):
# continue
# create_ssl = True
# if create_ssl:
# self._create_mysql_ssl()
if "ssl-ca" not in conf:
conf = re.sub(r'\[mysqld\]', '[mysqld]' + ssl_original_path, conf)
conf = re.sub('skip_ssl\n', '', conf)
public.writeFile(conf_file, conf)
# public.ExecShell('chown mysql.mysql /www/server/data/*.pem')
return public.return_msg_gettext(True, public.lang("Open successfully, take effect after manually restarting the database"))
# 检查mysqlssl状态
def check_mysql_ssl_status(self, get):
mysql_obj = panelMysql.panelMysql()
result = mysql_obj.query("show variables like 'have_ssl';")
if not os.path.exists('/www/server/data/ssl.zip'):
if os.path.exists('/www/server/mysql/mysql-test/std_data/client-cert.pem'):
public.ExecShell(
"cd /www/server/mysql/mysql-test/std_data/ && zip -q /www/server/data/ssl.zip client-cert.pem client-key.pem cacert.pem")
try:
if result and result[0][1] == "YES":
return True
return False
except:
return False
# 判断数据库是否存在—从MySQL
def database_exists_for_mysql(self, mysql_obj, dataName):
databases_tmp = self.map_to_list(mysql_obj.query('show databases'))
if not isinstance(databases_tmp, list):
return True
for i in databases_tmp:
if i[0] == dataName:
return True
return False
# 创建用户
def __CreateUsers(self, dbname, username, password, address, ssl=None):
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
mysql_obj.execute("CREATE USER `%s`@`localhost` IDENTIFIED BY '%s'" % (username, password))
result = mysql_obj.execute("grant all privileges on `%s`.* to `%s`@`localhost`" % (dbname, username))
if str(result).find('1044') != -1:
mysql_obj.execute(
"grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER,CREATE TEMPORARY TABLES,LOCK TABLES,EXECUTE,CREATE VIEW,SHOW VIEW,EVENT,TRIGGER on `%s`.* to `%s`@`localhost`" % (
dbname, username))
if not ssl:
mysql_obj.execute("update mysql.user set ssl_type='' where user='%s' and host='localhost'" % (username))
for a in address.split(','):
mysql_obj.execute("CREATE USER `%s`@`%s` IDENTIFIED BY '%s'" % (username, a, password))
result = mysql_obj.execute("grant all privileges on `%s`.* to `%s`@`%s`" % (dbname, username, a))
if str(result).find('1044') != -1:
mysql_obj.execute(
"grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER,CREATE TEMPORARY TABLES,LOCK TABLES,EXECUTE,CREATE VIEW,SHOW VIEW,EVENT,TRIGGER on `%s`.* to `%s`@`%s` %s" % (
dbname, username, a, ssl))
mysql_obj.execute("flush privileges")
# 检查是否在回收站
def CheckRecycleBin(self, name):
try:
u_name = self.db_name_to_unicode(name)
for n in os.listdir('/www/.Recycle_bin'):
if n.find('BTDB_' + name + '_t_') != -1: return True
if n.find('BTDB_' + u_name + '_t_') != -1: return True
return False
except:
return False
# 检测数据库执行错误
def IsSqlError(self, mysqlMsg):
mysqlMsg = str(mysqlMsg)
if "MySQLdb" in mysqlMsg: return public.return_msg_gettext(False, public.lang("MySQLdb component is missing! <br>Please enter SSH and run the command: pip install mysql-python"))
if "2002," in mysqlMsg or '2003,' in mysqlMsg: return public.return_msg_gettext(False, public.lang("ERROR to connect database, pls check database status!"))
if "using password:" in mysqlMsg: return public.return_msg_gettext(False, public.lang("Mysql root or user password is incorrect, please try to reset!"))
if "Connection refused" in mysqlMsg: return public.return_msg_gettext(False, public.lang("ERROR to connect database, pls check database status!"))
if "1133" in mysqlMsg: return public.return_msg_gettext(False, public.lang("Database user does NOT exist!"))
if "3679" in mysqlMsg: return public.returnMsg(False, public.lang("Slave database deletion failed, data directory does not exist!"))
if "libmysqlclient" in mysqlMsg:
self.rep_lnk()
public.ExecShell("pip uninstall mysql-python -y")
public.ExecShell("pip install pymysql")
public.writeFile('data/restart.pl', 'True')
return public.return_msg_gettext(False, public.lang("Execution failed, attempted auto repair, please try again later!"))
return None
def rep_lnk(self):
shell_cmd = '''
Setup_Path=/www/server/mysql
#删除软链
DelLink()
{
rm -f /usr/bin/mysql*
rm -f /usr/lib/libmysql*
rm -f /usr/lib64/libmysql*
rm -f /usr/bin/myisamchk
rm -f /usr/bin/mysqldump
rm -f /usr/bin/mysql
rm -f /usr/bin/mysqld_safe
rm -f /usr/bin/mysql_config
}
#设置软件链
SetLink()
{
ln -sf ${Setup_Path}/bin/mysql /usr/bin/mysql
ln -sf ${Setup_Path}/bin/mysqldump /usr/bin/mysqldump
ln -sf ${Setup_Path}/bin/myisamchk /usr/bin/myisamchk
ln -sf ${Setup_Path}/bin/mysqld_safe /usr/bin/mysqld_safe
ln -sf ${Setup_Path}/bin/mysqlcheck /usr/bin/mysqlcheck
ln -sf ${Setup_Path}/bin/mysql_config /usr/bin/mysql_config
rm -f /usr/lib/libmysqlclient.so.16
rm -f /usr/lib64/libmysqlclient.so.16
rm -f /usr/lib/libmysqlclient.so.18
rm -f /usr/lib64/libmysqlclient.so.18
rm -f /usr/lib/libmysqlclient.so.20
rm -f /usr/lib64/libmysqlclient.so.20
rm -f /usr/lib/libmysqlclient.so.21
rm -f /usr/lib64/libmysqlclient.so.21
if [ -f "${Setup_Path}/lib/libmysqlclient.so.18" ];then
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.20
elif [ -f "${Setup_Path}/lib/mysql/libmysqlclient.so.18" ];then
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.18 /usr/lib64/libmysqlclient.so.20
elif [ -f "${Setup_Path}/lib/libmysqlclient.so.16" ];then
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.20
elif [ -f "${Setup_Path}/lib/mysql/libmysqlclient.so.16" ];then
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.16 /usr/lib64/libmysqlclient.so.20
elif [ -f "${Setup_Path}/lib/libmysqlclient_r.so.16" ];then
ln -sf ${Setup_Path}/lib/libmysqlclient_r.so.16 /usr/lib/libmysqlclient_r.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient_r.so.16 /usr/lib64/libmysqlclient_r.so.16
elif [ -f "${Setup_Path}/lib/mysql/libmysqlclient_r.so.16" ];then
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient_r.so.16 /usr/lib/libmysqlclient_r.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient_r.so.16 /usr/lib64/libmysqlclient_r.so.16
elif [ -f "${Setup_Path}/lib/libmysqlclient.so.20" ];then
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.20
elif [ -f "${Setup_Path}/lib/libmysqlclient.so.21" ];then
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib64/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib/libmysqlclient.so.21
ln -sf ${Setup_Path}/lib/libmysqlclient.so.21 /usr/lib64/libmysqlclient.so.21
elif [ -f "${Setup_Path}/lib/libmariadb.so.3" ]; then
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib64/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib/libmysqlclient.so.21
ln -sf ${Setup_Path}/lib/libmariadb.so.3 /usr/lib64/libmysqlclient.so.21
elif [ -f "${Setup_Path}/lib/mysql/libmysqlclient.so.20" ];then
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.16
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.18
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib/libmysqlclient.so.20
ln -sf ${Setup_Path}/lib/mysql/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.20
fi
}
DelLink
SetLink
'''
return public.ExecShell(shell_cmd)
# 删除数据库
def DeleteDatabase(self, get):
# try:
id = get['id']
name = get['name']
find = public.M('databases').where("id=?", (id,)).field(
'id,sid,pid,name,username,password,accept,ps,addtime,db_type').find()
if not find: return public.return_msg_gettext(False, public.lang("Database [{}] does not exist!", name))
self.sid = find['sid']
if find['db_type'] in ['0', 0] or self.sid: # 删除本地数据库
if os.path.exists('data/recycle_bin_db.pl') and not self.sid: return self.DeleteToRecycleBin(name)
accept = find['accept']
username = find['username']
# 删除MYSQL
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj: return public.return_msg_gettext(False, public.lang("Database [{}] connection failed", name))
result = mysql_obj.execute("drop database `" + name + "`")
isError = self.IsSqlError(result)
if isError != None: return isError
users = mysql_obj.query("select Host from mysql.user where User='" + username + "' AND Host!='localhost'")
mysql_obj.execute("drop user '" + username + "'@'localhost'")
for us in users:
mysql_obj.execute("drop user '" + username + "'@'" + us[0] + "'")
mysql_obj.execute("flush privileges")
# 删除SQLITE
public.M('databases').where("id=?", (id,)).delete()
public.write_log_gettext("Database manager", 'Successfully deleted database [{}]!', (name,))
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
# except Exception as ex:
# public.write_log_gettext("Database manager",'Failed to delete database [{}]!, {}',(get.name , str(ex)))
# return public.return_msg_gettext(False, public.lang("Failed to delete"))
def db_name_to_unicode(self, name):
'''
@name 中文数据库名转换为Unicode编码
@author hwliang<2021-12-20>
@param name<string> 数据库名
@return name<string> Unicode编码的数据库名
'''
name = name.replace('.', '@002e')
name = name.replace('-', '@002d')
return name.encode("unicode_escape").replace(b"\\u", b"@").decode()
# 删除数据库到回收站
def DeleteToRecycleBin(self, name):
import json
data = public.M('databases').where("name=?", (name,)).field(
'id,pid,name,username,password,accept,ps,addtime').find()
username = data['username']
panelMysql.panelMysql().execute("drop user '" + username + "'@'localhost'")
users = panelMysql.panelMysql().query(
"select Host from mysql.user where User='" + username + "' AND Host!='localhost'")
if isinstance(users, str):
return public.return_msg_gettext(False, public.lang("Delete failed, failed to connect to database!"))
try:
for us in users:
panelMysql.panelMysql().execute("drop user '" + username + "'@'" + us[0] + "'")
except Exception:
pass
panelMysql.panelMysql().execute("flush privileges")
rPath = '/www/.Recycle_bin/'
data['rmtime'] = int(time.time())
u_name = self.db_name_to_unicode(name)
rm_path = '{}/BTDB_{}_t_{}'.format(rPath, u_name, data['rmtime'])
if os.path.exists(rm_path): rm_path += '.1'
rm_config_file = '{}/config.json'.format(rm_path)
datadir = public.get_datadir()
db_path = '{}/{}'.format(datadir, u_name)
if not os.path.exists(db_path):
return public.return_msg_gettext(False, public.lang("The database data does not exist!"))
public.ExecShell("mv -f {} {}".format(db_path, rm_path))
if not os.path.exists(rm_path):
return public.return_msg_gettext(False, public.lang("Failed to move database data to the recycle bin!"))
public.writeFile(rm_config_file, json.dumps(data))
# public.writeFile(rPath + 'BTDB_' + name +'_t_' + str(time.time()),json.dumps(data))
public.M('databases').where("name=?", (name,)).delete()
public.write_log_gettext("Database manager", 'Successfully deleted database [{}]!', (name,))
return public.return_msg_gettext(True, public.lang("Database moved to recycle bin!"))
# 永久删除数据库
def DeleteTo(self, filename):
import json
if os.path.isfile(filename):
data = json.loads(public.readFile(filename))
if public.M('databases').where("name=?", (data['name'],)).count():
os.remove(filename)
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
else:
if os.path.exists(filename):
try:
data = json.loads(public.readFile(os.path.join(filename, "config.json")))
except:
return public.returnMsg(False, public.lang("Recycle Bin does not exist for this database!"))
else:
return public.returnMsg(False, public.lang("Recycle Bin does not exist for this database!"))
db_obj = panelMysql.panelMysql()
if self.database_exists_for_mysql(db_obj, data['name']):
u_name = self.db_name_to_unicode(data['name'])
datadir = public.get_datadir()
db_path = '{}/{}'.format(datadir, u_name)
if not os.path.exists(db_path):
os.makedirs(db_path)
public.ExecShell("chown mysql:mysql {}".format(db_path))
result = db_obj.execute("drop database `" + data['name'] + "`")
isError = self.IsSqlError(result)
if isError != None: return isError
db_obj.execute("drop user '" + data['username'] + "'@'localhost'")
users = db_obj.query(
"select Host from mysql.user where User='" + data['username'] + "' AND Host!='localhost'")
for us in users:
db_obj.execute("drop user '" + data['username'] + "'@'" + us[0] + "'")
db_obj.execute("flush privileges")
if os.path.isfile(filename):
os.remove(filename)
else:
import shutil
shutil.rmtree(filename)
try:
public.write_log_gettext("Database manager", 'Successfully deleted database [{}]!', (data['name'],))
except:
pass
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
# 恢复数据库
def RecycleDB(self, filename):
import json
_isdir = False
if os.path.isfile(filename):
data = json.loads(public.readFile(filename))
else:
re_config_file = filename + '/config.json'
data = json.loads(public.readFile(re_config_file))
u_name = self.db_name_to_unicode(data['name'])
db_path = "{}/{}".format(public.get_datadir(), u_name)
if os.path.exists(db_path):
return public.return_msg_gettext(False, public.lang("There is a database with the same name in the current database. To ensure data security, stop recovery!"))
_isdir = True
if public.M('databases').where("name=?", (data['name'],)).count():
if not _isdir: os.remove(filename)
return public.return_msg_gettext(True, public.lang("Database recovered!"))
if not _isdir:
os.remove(filename)
else:
public.ExecShell('mv -f {} {}'.format(filename, db_path))
if not os.path.exists(db_path):
return public.return_msg_gettext(False, public.lang("Data recovery failed!"))
db_config_file = "{}/config.json".format(db_path)
if os.path.exists(db_config_file): os.remove(db_config_file)
# 设置文件权限
public.ExecShell("chown -R mysql:mysql {}".format(db_path))
public.ExecShell("chmod -R 660 {}".format(db_path))
public.ExecShell("chmod 700 {}".format(db_path))
self.__CreateUsers(data['name'], data['username'], data['password'], data['accept'])
public.M('databases').add('id,pid,name,username,password,accept,ps,addtime', (
data['id'], data['pid'], data['name'], data['username'], data['password'], data['accept'], data['ps'],
data['addtime']))
return public.return_msg_gettext(True, public.lang("Database recovered!"))
# 设置ROOT密码
def SetupPassword(self, get):
password = get['password'].strip()
try:
if not password: return public.return_msg_gettext(False, public.lang("Root password cannot be empty"))
rep = r"^[\w@\.\?\-\_\>\<\~\!\#\$\%\^\&\*\(\)]+$"
if not re.match(rep, password): return public.return_msg_gettext(False, public.lang("Database password cannot contain special characters!"))
self.sid = get.get('sid/d', 0)
# 修改MYSQL
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
result = mysql_obj.query("show databases")
isError = self.IsSqlError(result)
is_modify = True
if isError != None and not self.sid:
# 尝试使用新密码
public.M('config').where("id=?", (1,)).setField('mysql_root', password)
result = mysql_obj.query("show databases")
isError = self.IsSqlError(result)
if isError != None:
public.ExecShell(
"cd /www/server/panel && " + public.get_python_bin() + " tools.py root \"" + password + "\"")
is_modify = False
if is_modify:
admin_user = 'root'
m_version = public.readFile(public.GetConfigValue('setup_path') + '/mysql/version.pl')
if self.sid:
admin_user = mysql_obj._USER
m_version = mysql_obj.query('select version();')[0][0]
if m_version.find('5.7') == 0 or m_version.find('8.0') == 0:
accept = self.map_to_list(
mysql_obj.query("select Host from mysql.user where User='{}'".format(admin_user)))
for my_host in accept:
mysql_obj.execute(
"UPDATE mysql.user SET authentication_string='' WHERE User='{}' and Host='{}'".format(
admin_user, my_host[0]))
mysql_obj.execute(
"ALTER USER `%s`@`%s` IDENTIFIED BY '%s'" % (admin_user, my_host[0], password))
# elif m_version.find('10.5.') != -1 or m_version.find('10.4.') != -1:
elif any(mariadb_ver in m_version for mariadb_ver in
['10.5.', '10.4.', '10.6.', '10.7.', '10.11.', '11.3.']):
accept = self.map_to_list(
mysql_obj.query("select Host from mysql.user where User='{}'".format(admin_user)))
for my_host in accept:
mysql_obj.execute(
"ALTER USER `%s`@`%s` IDENTIFIED BY '%s'" % (admin_user, my_host[0], password))
else:
result = mysql_obj.execute(
"update mysql.user set Password=password('" + password + "') where User='{}'".format(
admin_user))
mysql_obj.execute("flush privileges")
msg = public.lang("Successfully modified root password!")
# 修改SQLITE
if self.sid:
public.M('database_servers').where('id=?', self.sid).setField('db_password', password)
public.write_log_gettext("Database manager", "Change the password of the remote MySQL server")
else:
public.M('config').where("id=?", (1,)).setField('mysql_root', password)
public.write_log_gettext("Database manager", 'Successfully modified root password!')
session['config']['mysql_root'] = password
return public.return_msg_gettext(True, msg)
except Exception as ex:
return public.return_msg_gettext(False, 'Failed to modify ' + str(ex))
# 修改用户密码
def ResDatabasePassword(self, get):
# try:
newpassword = get['password']
username = get['name']
id = get['id']
if not newpassword: return public.return_msg_gettext(False, 'Database [{}] password cannot be empty',
(username,))
db_find = public.M('databases').where('id=?', (id,)).find()
name = db_find['name']
rep = r"^[\w@\.\?\-\_\>\<\~\!\#\$\%\^\&\*\(\)]+$"
if not re.match(rep, newpassword): return public.return_msg_gettext(False, public.lang("Database password cannot contain special characters!"))
# 修改MYSQL
self.sid = db_find['sid']
if self.sid and username == 'root': return public.returnMsg(False, public.lang("Cannot change the root password of the remote database"))
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
m_version = public.readFile(public.GetConfigValue('setup_path') + '/mysql/version.pl')
if self.sid:
m_version = mysql_obj.query('select version();')[0][0]
if m_version.find('5.7') == 0 or m_version.find('8.0') == 0:
accept = self.map_to_list(
mysql_obj.query("select Host from mysql.user where User='" + name + "' AND Host!='localhost'"))
mysql_obj.execute("update mysql.user set authentication_string='' where User='" + username + "'")
result = mysql_obj.execute("ALTER USER `%s`@`localhost` IDENTIFIED BY '%s'" % (username, newpassword))
for my_host in accept:
mysql_obj.execute("ALTER USER `%s`@`%s` IDENTIFIED BY '%s'" % (username, my_host[0], newpassword))
elif m_version.find('10.5.') != -1 or m_version.find('10.4.') != -1:
accept = self.map_to_list(
mysql_obj.query("select Host from mysql.user where User='" + name + "' AND Host!='localhost'"))
result = mysql_obj.execute("ALTER USER `%s`@`localhost` IDENTIFIED BY '%s'" % (username, newpassword))
for my_host in accept:
mysql_obj.execute("ALTER USER `%s`@`%s` IDENTIFIED BY '%s'" % (username, my_host[0], newpassword))
else:
result = mysql_obj.execute(
"update mysql.user set Password=password('" + newpassword + "') where User='" + username + "'")
isError = self.IsSqlError(result)
if isError != None: return isError
mysql_obj.execute("flush privileges")
# if result==False: return public.return_msg_gettext(False, public.lang("Failed to modify, database user does not exist!"))
# 修改SQLITE
if int(id) > 0:
public.M('databases').where("id=?", (id,)).setField('password', newpassword)
else:
public.M('config').where("id=?", (id,)).setField('mysql_root', newpassword)
session['config']['mysql_root'] = newpassword
public.write_log_gettext("Database manager", 'Successfully modifyied password for database [{}]!', (name,))
return public.return_msg_gettext(True, 'Successfully modifyied password for database [{}]!', (name,))
# except Exception as ex:
# import traceback
# public.write_log_gettext("Database manager", 'Failed to modify password for database [{}]!',(username,traceback.format_exc(limit=True).replace('\n','<br>')))
# return public.return_msg_gettext(False,'Failed to modify password for database [{}]!',(name,))
# 备份
def ToBackup(self, get):
# try:
import shlex
id = get['id']
db_find = public.M('databases').where("id=?", (id,)).find()
name = db_find['name']
fileName = name + '_' + time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.sql.gz'
backupName = session['config']['backup_path'] + '/database/' + fileName
mysqldump_bin = public.get_mysqldump_bin()
if db_find['db_type'] in ['0', 0]:
# 本地数据库
result = panelMysql.panelMysql().execute("show databases")
isError = self.IsSqlError(result)
if isError: return isError
root = public.M('config').where('id=?', (1,)).getField('mysql_root')
if not os.path.exists(session['config']['backup_path'] + '/database'): public.ExecShell(
'mkdir -p ' + session['config']['backup_path'] + '/database')
if not self.mypass(True, root): return public.return_msg_gettext(False, public.lang("Database configuration file failed to get checked, please check if MySQL configuration file exists [/etc/my.cnf]"))
try:
password = public.M('config').where('id=?', (1,)).getField('mysql_root')
if not password: return public.returnMsg(False, public.lang("Database password cannot be empty"))
password = shlex.quote(str(password))
os.environ["MYSQL_PWD"] = password
public.ExecShell(
mysqldump_bin + " -R -E --triggers=false --default-character-set=" + public.get_database_character(
name) + " --force --opt \"" + name + "\" -u root -p" + password + " | gzip > " + backupName)
except Exception as e:
raise
finally:
os.environ["MYSQL_PWD"] = ""
self.mypass(False, root)
elif db_find['db_type'] in ['1', 1]:
# 远程数据库
try:
conn_config = json.loads(db_find['conn_config'])
res = self.CheckCloudDatabase(conn_config)
if isinstance(res, dict): return res
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = password
public.ExecShell(mysqldump_bin + " -h " + conn_config['db_host'] + " -P " + str(int(conn_config[
'db_port'])) + " -R -E --triggers=false --default-character-set=" + public.get_database_character(
name) + " --force --opt \"" + str(db_find['name']) + "\" -u " + str(
conn_config['db_user']) + " -p" + password + " | gzip > " + backupName)
except Exception as e:
raise
finally:
os.environ["MYSQL_PWD"] = ""
elif db_find['db_type'] in ['2', 2]:
try:
conn_config = public.M('database_servers').where('id=?', db_find['sid']).find()
res = self.CheckCloudDatabase(conn_config)
if isinstance(res, dict): return res
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = password
public.ExecShell(mysqldump_bin + " -h " + conn_config['db_host'] + " -P " + str(int(conn_config[
'db_port'])) + " -R -E --triggers=false --default-character-set=" + public.get_database_character(
name) + " --force --opt \"" + str(db_find['name']) + "\" -u " + str(
conn_config['db_user']) + " -p" + str(conn_config['db_password']) + " | gzip > " + backupName)
except Exception as e:
raise
finally:
os.environ["MYSQL_PWD"] = ""
else:
return public.return_msg_gettext(False, public.lang("Unsupported database type"))
if not os.path.exists(backupName): return public.return_msg_gettext(False, public.lang("Backup error!"))
sql = public.M('backup')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
sql.add('type,name,pid,filename,size,addtime', (1, fileName, id, backupName, 0, addTime))
public.write_log_gettext("Database manager", "Backup database [{}] succeed!", (name,))
return public.return_msg_gettext(True, public.lang("Backup Succeeded!"))
# except Exception as ex:
# public.write_log_gettext("数据库管理", "备份数据库[" + name + "]失败 => " + str(ex))
# return public.return_msg_gettext(False, public.lang("备份失败!"))
# 删除备份文件
def DelBackup(self, get):
try:
id = get.id
where = "id=?"
backup_info = public.M('backup').where(where, (id,)).find()
filename = backup_info['filename']
if os.path.exists(filename): os.remove(filename)
db_name = ''
if filename == 'qiniu':
name = backup_info['name']
public.ExecShell(public.get_python_bin() + " " + public.GetConfigValue(
'setup_path') + '/panel/script/backup_qiniu.py delete_file ' + name)
public.M('backup').where(where, (id,)).delete()
# 取实际
pid = backup_info['pid']
db_name = public.M('databases').where('id=?', (pid,)).getField('name')
public.write_log_gettext("Database manager", 'Successfully deleted backup [{}] for database [{}]!',
(db_name, filename))
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
except Exception as ex:
public.write_log_gettext("Database manager", 'Failed to delete backup [{}] for database [{}]! => {}',
(db_name, filename, str(ex)))
return public.return_msg_gettext(False, public.lang("Failed to delete"))
# 导入
def InputSql(self, get):
# try:
import shlex
name = get['name']
file = get['file']
if "|" in file:
file = file.split('|')[-1]
root = public.M('config').where('id=?', (1,)).getField('mysql_root')
tmp = file.split('.')
exts = ['sql', 'gz', 'zip']
ext = tmp[len(tmp) - 1]
if ext not in exts:
return public.return_msg_gettext(False, public.lang("Select sql/gz/zip file!"))
db_find = public.M('databases').where('name=?', name).find()
mysql_obj = public.get_mysql_obj_by_sid(db_find['sid'])
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
result = mysql_obj.execute("show databases")
isError = self.IsSqlError(result)
if isError: return isError
isgzip = False
mysql_bin = public.get_mysql_bin()
if ext != 'sql':
import panel_restore
tmp = file.split('/')
tmpFile = tmp[len(tmp) - 1]
tmpFile = tmpFile.replace('.sql.' + ext, '.sql')
tmpFile = tmpFile.replace('.' + ext, '.sql')
tmpFile = tmpFile.replace('tar.', '')
# return tmpFile
backupPath = session['config']['backup_path'] + '/database'
if "|" in file:
panel_restore.panel_restore().restore_db_backup(get)
download_msg = panel_restore.panel_restore().restore_db_backup(get)
if not download_msg['status']:
return download_msg
input_path = os.path.join(backupPath, tmpFile)
# 备份文件的路径
input_path2 = os.path.join(os.path.dirname(file), tmpFile)
if ext == 'zip':
public.ExecShell("cd " + backupPath + " && unzip " + '"' + file + '"')
else:
public.ExecShell("cd " + backupPath + " && tar zxf " + '"' + file + '"')
if not os.path.exists(input_path):
# 兼容从备份文件所在目录恢复
if not os.path.exists(input_path2):
public.ExecShell("cd " + backupPath + " && gunzip -q " + '"' + file + '"')
isgzip = True
else:
input_path = input_path2
if not os.path.exists(input_path) or tmpFile == '':
if tmpFile and os.path.isfile(input_path2):
input_path = input_path2
else:
return public.return_msg_gettext(False, 'Configuration file not exist', (tmpFile,))
try:
if db_find['db_type'] in ['0', 0]:
password = public.M('config').where('id=?', (1,)).getField('mysql_root')
password = shlex.quote(str(password))
os.environ["MYSQL_PWD"] = str(password)
public.ExecShell(mysql_bin + " -uroot -p" + str(
password) + " --force \"" + name + "\" < " + '"' + input_path + '"')
elif db_find['db_type'] in ['1', 1]:
conn_config = json.loads(db_find['conn_config'])
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = str(password)
public.ExecShell(mysql_bin + " -h " + conn_config['db_host'] + " -P " + str(
int(conn_config['db_port'])) + " -u" + str(conn_config['db_user']) + " -p" + str(
password) + " --force \"" + name + "\" < " + '"' + input_path + '"')
elif db_find['db_type'] in ['2', 2]:
conn_config = public.M('database_servers').where('id=?', db_find['sid']).find()
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = str(password)
public.ExecShell(mysql_bin + " -h " + conn_config['db_host'] + " -P " + str(
int(conn_config['db_port'])) + " -u" + str(conn_config['db_user']) + " -p" + str(
password) + " --force \"" + name + "\" < " + '"' + input_path + '"')
except Exception as e:
raise
finally:
os.environ["MYSQL_PWD"] = ""
if isgzip:
public.ExecShell('cd ' + os.path.dirname(input_path) + ' && gzip ' + file.split('/')[-1][:-3])
else:
public.ExecShell("rm -f " + input_path)
else:
try:
if db_find['db_type'] in ['0', 0]:
password = public.M('config').where('id=?', (1,)).getField('mysql_root')
password = shlex.quote(str(password))
os.environ["MYSQL_PWD"] = password
public.ExecShell(
mysql_bin + " -uroot -p" + password + " --force \"" + name + "\" < " + '"' + file + '"')
elif db_find['db_type'] in ['1', 1]:
conn_config = json.loads(db_find['conn_config'])
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = password
public.ExecShell(mysql_bin + " -h " + conn_config['db_host'] + " -P " + str(
int(conn_config['db_port'])) + " -u" + str(conn_config['db_user']) + " -p" + str(
password) + " --force \"" + name + "\" < " + '"' + file + '"')
elif db_find['db_type'] in ['2', 2]:
conn_config = public.M('database_servers').where('id=?', db_find['sid']).find()
password = shlex.quote(str(conn_config['db_password']))
os.environ["MYSQL_PWD"] = password
public.ExecShell(mysql_bin + " -h " + conn_config['db_host'] + " -P " + str(
int(conn_config['db_port'])) + " -u" + str(conn_config['db_user']) + " -p" + str(
password) + " --force \"" + name + "\" < " + '"' + file + '"')
except Exception as e:
raise
finally:
os.environ["MYSQL_PWD"] = ""
public.write_log_gettext("Database manager", 'Successfully imported database [{}]', (name,))
return public.return_msg_gettext(True, public.lang("Successfully imported database!"))
# except Exception as ex:
# public.WriteLog("TYPE_DATABASE", 'DATABASE_INPUT_ERR',(name,str(ex)))
# return public.returnMsg(False, public.lang("DATABASE_INPUT_ERR"))
# 同步数据库到服务器
def SyncToDatabases(self, get):
# result = panelMysql.panelMysql().execute("show databases")
# isError=self.IsSqlError(result)
# if isError: return isError
type = int(get['type'])
n = 0
sql = public.M('databases')
if type == 0:
data = sql.field('id,sid,name,username,password,accept,db_type').where("type='MySQL'", ()).select()
for value in data:
if value['db_type'] in ['1', 1]:
continue # 跳过远程数据库
result = self.ToDataBase(value)
if result == 1: n += 1
else:
import json
data = json.loads(get.ids)
for value in data:
find = sql.where("id=?", (value,)).field('id,sid,name,username,password,accept').find()
result = self.ToDataBase(find)
if result == 1: n += 1
# 当只同步1个数据库时不返回成功数量
if n == 1:
return public.returnMsg(True, public.lang("Synchronization succeeded"))
elif n == 0:
# 失败
return public.returnMsg(False, public.lang("Sync failed"))
else:
return public.return_msg_gettext(True, 'Sync {} database(s) from server!', (str(n),))
# 配置
def mypass(self, act, password=None):
conf_file = '/etc/my.cnf'
conf_file_bak = '/etc/my.cnf.bak'
if os.path.getsize(conf_file) > 2:
public.writeFile(conf_file_bak, public.readFile(conf_file))
public.set_mode(conf_file_bak, 600)
public.set_own(conf_file_bak, 'mysql')
elif os.path.getsize(conf_file_bak) > 2:
public.writeFile(conf_file, public.readFile(conf_file_bak))
public.set_mode(conf_file, 600)
public.set_own(conf_file, 'mysql')
public.ExecShell("sed -i '/user=root/d' {}".format(conf_file))
public.ExecShell("sed -i '/password=/d' {}".format(conf_file))
if act:
password = public.M('config').where('id=?', (1,)).getField('mysql_root')
mycnf = public.readFile(conf_file)
if not mycnf: return False
src_dump_re = r"\[mysqldump\][^.]"
sub_dump = "[mysqldump]\nuser=root\npassword=\"{}\"\n".format(password)
mycnf = re.sub(src_dump_re, sub_dump, mycnf)
if len(mycnf) > 100: public.writeFile(conf_file, mycnf)
return True
return True
# 添加到服务器
def ToDataBase(self, find):
# if find['username'] == 'bt_default': return 0
if len(find['password']) < 3:
find['username'] = find['name']
find['password'] = public.md5(str(time.time()) + find['name'])[0:10]
public.M('databases').where("id=?", (find['id'],)).save('password,username',
(find['password'], find['username']))
self.sid = find['sid']
mysql_obj = public.get_mysql_obj_by_sid(find['sid'])
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
result = mysql_obj.execute("create database `" + find['name'] + "`")
if "using password:" in str(result): return -1
if "Connection refused" in str(result): return -1
password = find['password']
# if find['password']!="" and len(find['password']) > 20:
# password = find['password']
self.__CreateUsers(find['name'], find['username'], password, find['accept'])
return 1
# 从服务器获取数据库
def SyncGetDatabases(self, get):
self.sid = get.get('sid/d', 0)
db_type = 0
if self.sid: db_type = 2
mysql_obj = public.get_mysql_obj_by_sid(self.sid)
if not mysql_obj: return public.returnMsg(False, public.lang("Failed to connect to the specified database"))
data = mysql_obj.query("show databases")
isError = self.IsSqlError(data)
if isError != None: return isError
users = mysql_obj.query(
"select User,Host from mysql.user where User!='root' AND Host!='localhost' AND Host!=''")
if type(users) == str: return public.returnMsg(False, users)
if type(users) != list: return public.returnMsg(False, public.GetMySQLError(users))
sql = public.M('databases')
nameArr = ['information_schema', 'performance_schema', 'mysql', 'sys']
n = 0
for value in data:
b = False
for key in nameArr:
if value[0] == key:
b = True
break
if b: continue
if sql.where("name=?", (value[0],)).count(): continue
host = '127.0.0.1'
for user in users:
if value[0] == user[0]:
host = user[1]
break
ps = public.lang("Edit notes")
if value[0] == 'test':
ps = public.lang("Test Database")
# XSS filter
if not re.match(r"^[\w+\.-]+$", value[0]): continue
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
if sql.table('databases').add('name,sid,db_type,username,password,accept,ps,addtime',
(value[0], self.sid, db_type, value[0], '', host, ps, addTime)): n += 1
return public.return_msg_gettext(True, 'Obtain {} database(s) from server!', (str(n),))
# 获取数据库权限
def GetDatabaseAccess(self, get):
name = get['name']
db_name = public.M('databases').where('username=?', name).getField('name')
mysql_obj = public.get_mysql_obj(db_name)
users = mysql_obj.query("select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
ssl_type = panelMysql.panelMysql().query("select ssl_type from mysql.user where User='%s'" % name)
isError = self.IsSqlError(users)
if isError != None: return isError
users = self.map_to_list(users)
try:
if ssl_type:
ssl_type = ssl_type[0][0]
except:
ssl_type = ""
if len(users) < 1:
return public.return_msg_gettext(True, {"permission": "127.0.0.1", "ssl": ssl_type})
accs = []
for c in users:
accs.append(c[0])
userStr = ','.join(accs)
return public.return_msg_gettext(True, {"permission": userStr, "ssl": ssl_type})
# 设置数据库权限
def SetDatabaseAccess(self, get):
ssl = ""
if hasattr(get, 'ssl'):
ssl = get.ssl
if ssl == "REQUIRE SSL" and not self.check_mysql_ssl_status(get):
return public.return_msg_gettext(False, public.lang("SSL is not enabled in the database, please open it in the Mysql manager first"))
name = get['name']
db_find = public.M('databases').where('username=?', (name,)).find()
db_name = db_find['name']
self.sid = db_find['sid']
mysql_obj = public.get_mysql_obj(db_name)
access = get['access'].strip()
if access in ['']: return public.return_msg_gettext(False, public.lang("The IP address cannot be empty!"))
password = public.M('databases').where("username=?", (name,)).getField('password')
result = mysql_obj.query("show databases")
isError = self.IsSqlError(result)
if isError != None: return isError
users = mysql_obj.query("select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
for us in users:
mysql_obj.execute("drop user '" + name + "'@'" + us[0] + "'")
self.__CreateUsers(db_name, name, password, access, ssl)
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
# 获取数据库配置信息
def GetMySQLInfo(self, get):
data = {}
try:
public.CheckMyCnf()
myfile = '/etc/my.cnf'
mycnf = public.readFile(myfile)
rep = "datadir\\s*=\\s*(.+)\n"
data['datadir'] = re.search(rep, mycnf).groups()[0]
rep = "port\\s*=\\s*([0-9]+)\\s*\n"
data['port'] = re.search(rep, mycnf).groups()[0]
except:
data['datadir'] = '/www/server/data'
data['port'] = '3306'
return data
# 修改数据库目录
def SetDataDir(self, get):
if get.datadir[-1] == '/': get.datadir = get.datadir[0:-1]
if len(get.datadir) > 32: return public.return_msg_gettext(False, public.lang("The data directory length cannot exceed 32 bits"))
# if not re.search(r"^[0-9A-Za-z_/\\]$+",get.datadir): return public.return_msg_gettext(False, public.lang("Special symbols cannot be included in the database path"))
if not os.path.exists(get.datadir): public.ExecShell('mkdir -p ' + get.datadir)
mysqlInfo = self.GetMySQLInfo(get)
if mysqlInfo['datadir'] == get.datadir: return public.return_msg_gettext(False, public.lang("The same as the current storage directory, file cannot be moved!"))
public.ExecShell('/etc/init.d/mysqld stop')
public.ExecShell(r'\cp -arf ' + mysqlInfo['datadir'] + '/* ' + get.datadir + '/')
public.ExecShell('chown -R mysql.mysql ' + get.datadir)
public.ExecShell('chmod -R 755 ' + get.datadir)
public.ExecShell('rm -f ' + get.datadir + '/*.pid')
public.ExecShell('rm -f ' + get.datadir + '/*.err')
public.CheckMyCnf()
myfile = '/etc/my.cnf'
mycnf = public.readFile(myfile)
public.writeFile('/etc/my_backup.cnf', mycnf)
mycnf = mycnf.replace(mysqlInfo['datadir'], get.datadir)
public.writeFile(myfile, mycnf)
public.ExecShell('/etc/init.d/mysqld start')
result = public.ExecShell('ps aux|grep mysqld|grep -v grep')
if len(result[0]) > 10:
public.writeFile('data/datadir.pl', get.datadir)
return public.return_msg_gettext(True, public.lang("Database moved!"))
else:
public.ExecShell('pkill -9 mysqld')
public.writeFile(myfile, public.readFile('/etc/my_backup.cnf'))
public.ExecShell('/etc/init.d/mysqld start')
return public.return_msg_gettext(False, public.lang("Failed to move file!"))
# 修改数据库端口
def SetMySQLPort(self, get):
myfile = '/etc/my.cnf'
mycnf = public.readFile(myfile)
rep = "port\\s*=\\s*([0-9]+)\\s*\n"
mycnf = re.sub(rep, 'port = ' + get.port + '\n', mycnf)
public.writeFile(myfile, mycnf)
public.ExecShell('/etc/init.d/mysqld restart')
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
# 获取错误日志
def GetErrorLog(self, get):
path = self.GetMySQLInfo(get)['datadir']
filename = ''
for n in os.listdir(path):
if len(n) < 5: continue
if n[-3:] == 'err':
filename = path + '/' + n
break
if not os.path.exists(filename): return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
if hasattr(get, 'close'):
public.writeFile(filename, '')
return public.return_msg_gettext(True, public.lang("log is empty"))
return public.GetNumLines(filename, 1000)
# 二进制日志开关
def BinLog(self, get):
status = getattr(get, "status", None)
mysql_cnf = public.readFile(self._MYSQL_CNF)
if mysql_cnf.find('#log-bin=mysql-bin') != -1:
if hasattr(get, 'status'): return public.return_msg_gettext(False, public.lang("0"))
log_bin_status = re.search("\nlog-bin", mysql_cnf)
is_off_bin_log = re.search("\nskip-log-bin", mysql_cnf)
bin_log_status = False
if log_bin_status and not is_off_bin_log:
bin_log_status = True
mysql_data_dir = self.GetMySQLInfo(get)['datadir']
if status is not None:
bin_log_total_size = 0
mysql_bin_index = os.path.join(mysql_data_dir, "mysql-bin.index")
mysql_bin_index_content = public.readFile(mysql_bin_index)
if mysql_bin_index_content is not False:
for name in str(mysql_bin_index_content).strip().split("\n"):
bin_log_path = os.path.join(mysql_data_dir, os.path.basename(name))
if os.path.isfile(bin_log_path):
bin_log_total_size += os.path.getsize(bin_log_path)
# return {"status": True, "msg": "ok", "data": {"binlog_status": bin_log_status, "size": bin_log_total_size}}
return public.return_msg_gettext(True, bin_log_total_size)
if bin_log_status is True: # 关闭 binlog 日志
master_slave_conf_1 = "/www/server/panel/plugin/masterslave/data.json"
master_slave_conf_2 = "/www/server/panel/plugin/mysql_replicate/config.json"
if os.path.exists(master_slave_conf_1):
# return {"status": False, "msg": "请先卸载【Mysql主从复制】插件后再关闭二进制日志", "data": {"binlog_status": bin_log_status}}
return public.return_msg_gettext(False, public.lang("Please uninstall the Mysql master-slave replication plugin before closing the binary log! !"))
if os.path.exists(master_slave_conf_2):
# return {"status": False, "msg": "请先卸载【Mysql主从复制重构版】插件后再关闭二进制日志", "data": {"binlog_status": bin_log_status}}
return public.return_msg_gettext(False, public.lang("Please uninstall the Mysql master-slave replication plugin before closing the binary log! !"))
if log_bin_status:
mysql_cnf = re.sub(r"\nlog-bin", "\n#log-bin", mysql_cnf)
mysql_cnf = re.sub(r"\nbinlog_format", "\n#binlog_format", mysql_cnf)
if not is_off_bin_log:
if re.search("\n#\\s*skip-log-bin", mysql_cnf):
mysql_cnf = re.sub("\n#\\s*skip-log-bin", "\nskip-log-bin", mysql_cnf)
else:
mysql_cnf = re.sub("\n#\\s*log-bin", "\nskip-log-bin\n#log-bin", mysql_cnf)
# public.ExecShell("rm -f {}/mysql-bin.*".format(mysql_data_dir))
else: # 开启 binlog 日志
if re.search("\n#\\s*log-bin", mysql_cnf):
mysql_cnf = re.sub("\n#\\s*log-bin", "\nlog-bin", mysql_cnf)
else:
mysql_cnf = re.sub("[mysqld]", "[mysqld]\nlog-bin=mysql-bin", mysql_cnf)
if re.search("\n#\\s*binlog_format", mysql_cnf):
mysql_cnf = re.sub("\n#\\s*binlog_format", "\nbinlog_format", mysql_cnf)
else:
mysql_cnf = re.sub("[mysqld]", "[mysqld]\nbinlog_format=mixed", mysql_cnf)
if is_off_bin_log:
mysql_cnf = re.sub("\nskip-log-bin", "\n#skip-log-bin", mysql_cnf)
public.writeFile(self._MYSQL_CNF, mysql_cnf)
public.ExecShell('sync')
public.ExecShell('/etc/init.d/mysqld restart')
return {"status": True, "msg": "{} Binary log successful, Please refresh manually".format("Enable" if not bin_log_status else "Disable"), "data": {"binlog_status": not bin_log_status}}
# 获取MySQL配置状态
def GetDbStatus(self, get):
result = {}
data = self.map_to_list(panelMysql.panelMysql().query('show variables'))
gets = ['table_open_cache', 'thread_cache_size', 'query_cache_type', 'key_buffer_size', 'query_cache_size',
'tmp_table_size', 'max_heap_table_size', 'innodb_buffer_pool_size', 'innodb_additional_mem_pool_size',
'innodb_log_buffer_size', 'max_connections', 'sort_buffer_size', 'read_buffer_size',
'read_rnd_buffer_size', 'join_buffer_size', 'thread_stack', 'binlog_cache_size']
result['mem'] = {}
for d in data:
try:
for g in gets:
if d[0] == g: result['mem'][g] = d[1]
except:
continue
if 'query_cache_type' in result['mem']:
if result['mem']['query_cache_type'] != 'ON': result['mem']['query_cache_size'] = '0'
return result
# 设置MySQL配置参数
def SetDbConf(self, get):
gets = ['key_buffer_size', 'query_cache_size', 'tmp_table_size', 'max_heap_table_size',
'innodb_buffer_pool_size', 'innodb_log_buffer_size', 'max_connections', 'query_cache_type',
'table_open_cache', 'thread_cache_size', 'sort_buffer_size', 'read_buffer_size', 'read_rnd_buffer_size',
'join_buffer_size', 'thread_stack', 'binlog_cache_size']
emptys = ['max_connections', 'query_cache_type', 'thread_cache_size', 'table_open_cache']
mycnf = public.readFile('/etc/my.cnf')
n = 0
m_version = public.readFile('/www/server/mysql/version.pl')
if not m_version: m_version = ''
for g in gets:
if g not in get:
continue
if m_version.find('8.') == 0 and g in ['query_cache_type', 'query_cache_size']:
n += 1
continue
s = 'M'
if n > 5 and not g in ['key_buffer_size', 'query_cache_size', 'tmp_table_size', 'max_heap_table_size',
'innodb_buffer_pool_size', 'innodb_log_buffer_size']: s = 'K'
if g in emptys: s = ''
if g in ['innodb_log_buffer_size']:
s = 'M'
if int(get[g]) < 8:
return public.return_msg_gettext(False, public.lang("innodb_log_buffer_size cannot be less than 8MB"))
rep = r'\s*' + g + r'\s*=\s*\d+(M|K|k|m|G)?\n'
c = g + ' = ' + get[g] + s + '\n'
if mycnf.find(g) != -1:
mycnf = re.sub(rep, '\n' + c, mycnf, 1)
else:
mycnf = mycnf.replace('[mysqld]\n', '[mysqld]\n' + c)
n += 1
public.writeFile('/etc/my.cnf', mycnf)
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
# 获取MySQL运行状态
def GetRunStatus(self, get):
import time
result = {}
data = panelMysql.panelMysql().query('show global status')
gets = ['Max_used_connections', 'Com_commit', 'Com_rollback', 'Questions', 'Innodb_buffer_pool_reads',
'Innodb_buffer_pool_read_requests', 'Key_reads', 'Key_read_requests', 'Key_writes',
'Key_write_requests', 'Qcache_hits', 'Qcache_inserts', 'Bytes_received', 'Bytes_sent',
'Aborted_clients', 'Aborted_connects', 'Created_tmp_disk_tables', 'Created_tmp_tables',
'Innodb_buffer_pool_pages_dirty', 'Opened_files', 'Open_tables', 'Opened_tables', 'Select_full_join',
'Select_range_check', 'Sort_merge_passes', 'Table_locks_waited', 'Threads_cached', 'Threads_connected',
'Threads_created', 'Threads_running', 'Connections', 'Uptime']
try:
if data[0] == 1045:
return public.return_msg_gettext(False, public.lang("MySQL password ERROR!"))
for d in data:
for g in gets:
try:
if d[0] == g: result[g] = d[1]
except:
pass
except:
return public.return_msg_gettext(False, str(data))
if not 'Run' in result and result:
result['Run'] = int(time.time()) - int(result['Uptime'])
m_version = public.readFile(public.GetConfigValue('setup_path') + '/mysql/version.pl')
if m_version.find('8.4') != -1 or m_version.find('9.0') != -1:
tmp = panelMysql.panelMysql().query('SHOW BINARY LOG STATUS')
else:
tmp = panelMysql.panelMysql().query('show master status')
try:
result['File'] = tmp[0][0]
result['Position'] = tmp[0][1]
except:
result['File'] = 'OFF'
result['Position'] = 'OFF'
return result
# 取慢日志
def GetSlowLogs(self, get):
path = self.GetMySQLInfo(get)['datadir'] + '/mysql-slow.log'
if not os.path.exists(path): return public.return_msg_gettext(False, public.lang("Log file does NOT exist!"))
return public.return_msg_gettext(True, public.GetNumLines(path, 100))
# 获取binlog文件列表
def GetMySQLBinlogs(self, get):
data_dir = self.GetMySQLInfo(get)["datadir"]
index_file = os.path.join(data_dir, "mysql-bin.index")
if not os.path.exists(index_file): return public.return_msg_gettext(False, public.lang("Binlog is not enabled or binlog file does not exist!"))
text = public.readFile(index_file)
m_version = public.readFile(public.GetConfigValue('setup_path') + '/mysql/version.pl')
if m_version.find('8.4') != -1 or m_version.find('9.0') != -1:
rows = panelMysql.panelMysql().query("SHOW BINARY LOG STATUS")
else:
rows = panelMysql.panelMysql().query("show master status")
current_log = ""
if not isinstance(rows, list):
return public.return_msg_gettext(False, public.lang("Mysql status is abnormal!"))
if len(rows) != 0:
current_log = rows[0][0]
bin_log = []
for item in text.split('\n'):
log_file = item.strip()
log_name = log_file.lstrip("./")
if not log_file: continue # 空行
bin_log_path = os.path.join(data_dir, log_name)
if not os.path.isfile(bin_log_path): continue
st = os.stat(bin_log_path)
bin_log.append({
"name": log_name,
"path": bin_log_path,
"size": st.st_size,
"last_modified": int(st.st_mtime),
"last_access": int(st.st_atime),
"current": current_log == log_name
})
return {"status": True, "msg": "ok", "data": bin_log}
def ClearMySQLBinlog(self, get):
if not hasattr(get, "days"):
return public.returnMsg(False, public.lang("Parameters are missing! days"))
if not str(get.days).isdigit():
return public.returnMsg(False, public.lang("Parameters are missing! days"))
days = int(get.days)
if days < 7: return public.return_msg_gettext(False, public.lang("To ensure data security, recent binlogs cannot be deleted!"))
rows = panelMysql.panelMysql().query("PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL {days} DAY)".format(days=days))
# public.print_log(rows)
# if rows: public.print_log(rows[0])
return public.return_msg_gettext(True, public.lang("Cleanup complete!"))
# 获取当前数据库信息
def GetInfo(self, get):
info = self.GetdataInfo(get)
return info
if info:
return info
else:
return public.return_msg_gettext(False, public.lang("Failed to get databases"))
# 修复表信息
def ReTable(self, get):
info = self.RepairTable(get)
if info:
return public.return_msg_gettext(True, public.lang("Successfully repaired!"))
else:
return public.return_msg_gettext(False, public.lang("Failed to repair!"))
# 优化表
def OpTable(self, get):
info = self.OptimizeTable(get)
if info:
return public.return_msg_gettext(True, public.lang("Successfully optimized!"))
else:
return public.return_msg_gettext(False, public.lang("Failed to optimize or already optimized"))
# 更改表引擎
def AlTable(self, get):
info = self.AlterTable(get)
if info:
return public.return_msg_gettext(True, public.lang("Successfully changed"))
else:
return public.return_msg_gettext(False, public.lang("Failed to change"))
def get_average_num(self, slist):
"""
@获取平均值
"""
count = len(slist)
limit_size = 1 * 1024 * 1024
if count <= 0: return limit_size
if len(slist) > 1:
slist = sorted(slist)
limit_size = int((slist[0] + slist[-1]) / 2 * 0.85)
return limit_size
def get_database_size(self, ids, is_pid=False):
"""
获取数据库大小
"""
result = {}
for id in ids:
if not is_pid:
x = public.M('databases').where('id=?', id).field('id,sid,pid,name,type,ps,addtime').find()
else:
x = public.M('databases').where('pid=?', id).field('id,sid,pid,name,ps,type,addtime').find()
if not x: continue
x['backup_count'] = public.M('backup').where("pid=? AND type=?", (x['id'], '1')).count()
if x['type'] == 'MySQL':
x['total'] = int(public.get_database_size_by_id(x['id']))
else:
try:
from panelDatabaseController import DatabaseController
project_obj = DatabaseController()
get = public.dict_obj()
get['data'] = {'db_id': x['id']}
get['mod_name'] = x['type'].lower()
get['def_name'] = 'get_database_size_by_id'
x['total'] = project_obj.model(get)
except:
x['total'] = int(public.get_database_size_by_id(x['id']))
result[x['name']] = x
return result
def check_del_data(self, get):
"""
@删除数据库前置检测
"""
ids = json.loads(get.ids)
slist = {};
result = [];
db_list_size = []
db_data = self.get_database_size(ids)
for key in db_data:
data = db_data[key]
if not data['id'] in ids: continue
db_addtime = public.to_date(times=data['addtime'])
data['score'] = int(time.time() - db_addtime) + data['total']
data['st_time'] = db_addtime
if data['total'] > 0: db_list_size.append(data['total'])
result.append(data)
slist['data'] = sorted(result, key=lambda x: x['score'], reverse=True)
slist['db_size'] = self.get_average_num(db_list_size)
return slist