Initial YakPanel commit
This commit is contained in:
1
class_v2/databaseModelV2/__init__.py
Normal file
1
class_v2/databaseModelV2/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
535
class_v2/databaseModelV2/base.py
Normal file
535
class_v2/databaseModelV2/base.py
Normal file
@@ -0,0 +1,535 @@
|
||||
# coding: utf-8
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
panelPath = '/www/server/panel'
|
||||
os.chdir(panelPath)
|
||||
if not panelPath + "/class/" in sys.path:
|
||||
sys.path.insert(0, panelPath + "/class/")
|
||||
import public, re
|
||||
from public.exceptions import HintException
|
||||
|
||||
|
||||
class databaseBase:
|
||||
def get_base_list(self, args, sql_type='mysql'):
|
||||
"""
|
||||
@获取数据库列表
|
||||
@type:数据库类型,MySQL,SQLServer
|
||||
"""
|
||||
search = ''
|
||||
if 'search' in args: search = args['search']
|
||||
|
||||
conditions = ''
|
||||
if '_' in search:
|
||||
cs = ''
|
||||
for i in search:
|
||||
if i == '_':
|
||||
cs += '/_'
|
||||
else:
|
||||
cs += i
|
||||
search = cs
|
||||
conditions = " escape '/'"
|
||||
|
||||
SQL = public.M('databases')
|
||||
|
||||
where = "lower(type) = lower('{}')".format(sql_type)
|
||||
if search:
|
||||
where += "AND (name like '%{search}%' or ps like '%{search}%'{conditions})".format(search=search,
|
||||
conditions=conditions)
|
||||
if 'db_type' in args:
|
||||
where += " AND db_type='{}'".format(args['db_type'])
|
||||
|
||||
if 'sid' in args:
|
||||
where += " AND sid='{}'".format(args['sid'])
|
||||
|
||||
order = "id desc"
|
||||
if hasattr(args, 'order'): order = args.order
|
||||
|
||||
info = {}
|
||||
rdata = {}
|
||||
|
||||
info['p'] = 1
|
||||
info['row'] = 20
|
||||
result = '1,2,3,4,5,8'
|
||||
info['count'] = SQL.where(where, ()).count()
|
||||
|
||||
if hasattr(args, 'limit'): info['row'] = int(args.limit)
|
||||
if hasattr(args, 'result'): result = args.result
|
||||
if hasattr(args, 'p'): info['p'] = int(args['p'])
|
||||
|
||||
import page
|
||||
# 实例化分页类
|
||||
page = page.Page()
|
||||
|
||||
info['uri'] = args
|
||||
info['return_js'] = ''
|
||||
if hasattr(args, 'tojs'):
|
||||
info['return_js'] = args.tojs
|
||||
|
||||
rdata['where'] = where
|
||||
|
||||
# 获取分页数据
|
||||
rdata['page'] = page.GetPage(info, result)
|
||||
# 取出数据
|
||||
rdata['data'] = SQL.where(where, ()).order(order).field(
|
||||
'id,sid,pid,name,username,password,accept,ps,addtime,type,db_type,conn_config'
|
||||
).limit(
|
||||
str(page.SHIFT) + ',' + str(page.ROW)
|
||||
).select()
|
||||
|
||||
if type(rdata['data']) == str:
|
||||
raise HintException("Database query error: " + rdata['data'])
|
||||
|
||||
for sdata in rdata['data']:
|
||||
backup_count = 0
|
||||
backup_list = public.S('backup').where("pid=? AND type=1", (sdata['id'],)).select()
|
||||
for backup in backup_list:
|
||||
# 清除本地不存在的, 云端保留
|
||||
if not os.path.exists(backup["filename"]) and backup["filename"].find("|") == -1:
|
||||
public.S('backup').where("id=? AND type=1", (backup['id'])).delete()
|
||||
continue
|
||||
backup_count += 1
|
||||
sdata['backup_count'] = backup_count
|
||||
sdata['conn_config'] = json.loads(sdata['conn_config'])
|
||||
return rdata
|
||||
|
||||
def get_databaseModel(self):
|
||||
'''
|
||||
获取数据库模型对象
|
||||
@db_type 数据库类型
|
||||
'''
|
||||
from panelDatabaseControllerV2 import DatabaseController
|
||||
|
||||
project_obj = DatabaseController()
|
||||
|
||||
return project_obj
|
||||
|
||||
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 = {}
|
||||
p = self.get_databaseModel()
|
||||
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,type,ps,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(id))
|
||||
else:
|
||||
try:
|
||||
|
||||
get = public.dict_obj()
|
||||
get['data'] = {'db_id': x['id']}
|
||||
get['mod_name'] = x['type'].lower()
|
||||
get['def_name'] = 'get_database_size_by_id'
|
||||
try:
|
||||
x['total'] = p.model(get)["message"]["result"]
|
||||
except:
|
||||
x['total'] = 0
|
||||
except:
|
||||
x['total'] = 0
|
||||
result[x['name']] = x
|
||||
|
||||
return result
|
||||
|
||||
def check_base_del_data(self, get):
|
||||
"""
|
||||
@删除数据库前置检测
|
||||
"""
|
||||
if not hasattr(get, 'ids'):
|
||||
raise HintException("Parameter 'ids' is required for deletion.")
|
||||
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
|
||||
|
||||
def get_test(self, args):
|
||||
|
||||
p = self.get_databaseModel()
|
||||
get = public.dict_obj()
|
||||
get['data'] = {'db_id': 18}
|
||||
get['mod_name'] = args['type'].lower()
|
||||
get['def_name'] = 'get_database_size_by_id'
|
||||
|
||||
return p.model(get)
|
||||
|
||||
def add_base_database(self, get, dtype):
|
||||
"""
|
||||
@添加数据库前置检测
|
||||
@return username 用户名
|
||||
data_name 数据库名
|
||||
data_pwd:数据库密码
|
||||
"""
|
||||
data_name = get['name'].strip().lower()
|
||||
if self.check_recyclebin(data_name):
|
||||
return public.returnMsg(False, public.lang(
|
||||
"Database [' + data_name + '] is already in recycle bin, please restore from recycle bin!"))
|
||||
|
||||
if len(data_name) > 16:
|
||||
return public.returnMsg(False, public.lang("Database name cannot be more than 16 characters!"))
|
||||
|
||||
if not hasattr(get, 'db_user'): get.db_user = data_name
|
||||
username = get.db_user.strip()
|
||||
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
|
||||
if username in checks or len(username) < 1:
|
||||
return public.returnMsg(False, public.lang("Database username is invalid!"))
|
||||
if data_name in checks or len(data_name) < 1:
|
||||
return public.returnMsg(False, public.lang("Database name is invalid!"))
|
||||
|
||||
reg = r"^\w+$"
|
||||
if not re.match(reg, data_name):
|
||||
return public.returnMsg(False, public.lang("Database name cannot contain special characters!"))
|
||||
|
||||
data_pwd = get['password']
|
||||
if len(data_pwd) < 1:
|
||||
data_pwd = public.md5(str(time.time()))[0:8]
|
||||
|
||||
if public.M('databases').where("(name=? or username=?) AND LOWER(type)=LOWER(?)",
|
||||
(data_name, username, dtype)).count():
|
||||
return public.returnMsg(False, public.lang("Database exists!"))
|
||||
|
||||
res = {
|
||||
'data_name': data_name,
|
||||
'username': username,
|
||||
'data_pwd': data_pwd,
|
||||
'status': True
|
||||
}
|
||||
return res
|
||||
|
||||
def delete_base_backup(self, get):
|
||||
"""
|
||||
@删除备份文件
|
||||
"""
|
||||
|
||||
id = get.id
|
||||
where = "id=?"
|
||||
obj = public.S("backup").where(where, (id,)).find()
|
||||
if not obj:
|
||||
return public.return_message(-1, 0, 'The specified backup file does not exist!')
|
||||
filename = obj.get("filename")
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
|
||||
pid = obj.get("pid")
|
||||
db_info = public.S("database").where("id=?", pid).find()
|
||||
db_type = db_info.get("type", "mysql")
|
||||
db_name = db_info.get("name", "unknown")
|
||||
public.M('backup').where(where, (id,)).delete()
|
||||
public.WriteLog(
|
||||
"TYPE_DATABASE",
|
||||
f"Successfully deleted backup [{filename}] for database [{db_type}-{db_name}]!"
|
||||
)
|
||||
return public.return_message(0, 0, 'DEL_SUCCESS')
|
||||
|
||||
# 检查是否在回收站
|
||||
def check_recyclebin(self, name):
|
||||
try:
|
||||
for n in os.listdir('{}/Recycle_bin'.format(public.get_setup_path())):
|
||||
if n.find('BTDB_' + name + '_t_') != -1: return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
# map to list
|
||||
def map_to_list(self, map_obj):
|
||||
try:
|
||||
if type(map_obj) != list and type(map_obj) != str: map_obj = list(map_obj)
|
||||
return map_obj
|
||||
except:
|
||||
return []
|
||||
|
||||
# ******************************************** 远程数据库 ******************************************/
|
||||
|
||||
def check_cloud_args(self, get, nlist=[]):
|
||||
"""
|
||||
验证参数是否合法
|
||||
@get param
|
||||
@args 参数列表
|
||||
"""
|
||||
for key in nlist:
|
||||
if not key in get:
|
||||
return public.return_message(-1, 0, public.lang("Parameter passing error, missing parameter {}!", key))
|
||||
return public.return_message(0, 0, "success")
|
||||
|
||||
def check_cloud_database(self, args):
|
||||
'''
|
||||
@检查远程数据库是否存在
|
||||
@conn_config param
|
||||
'''
|
||||
p = self.get_databaseModel()
|
||||
|
||||
get = public.dict_obj()
|
||||
get['data'] = args
|
||||
get['mod_name'] = args['type']
|
||||
get['def_name'] = 'check_cloud_database_status'
|
||||
return p.model(get)
|
||||
|
||||
def AddBaseCloudServer(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> 数据库备注
|
||||
@param type<string> 数据库类型,mysql/sqlserver/sqlite
|
||||
@return dict
|
||||
"""
|
||||
arrs = ['db_host', 'db_port', 'db_user', 'db_password', 'db_ps', 'type']
|
||||
if get.type == 'redis':
|
||||
arrs = ['db_host', 'db_port', 'db_password', 'db_ps', 'type']
|
||||
cRet = self.check_cloud_args(get, arrs)
|
||||
if isinstance(cRet, dict):
|
||||
return cRet
|
||||
|
||||
get['db_name'] = None
|
||||
res = self.check_cloud_database(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_message(-1, 0, 'The specified server already exists: [{}:{}]'.format(get['db_host'],
|
||||
get['db_port']))
|
||||
get['db_port'] = int(get['db_port'])
|
||||
pdata = {
|
||||
'db_host': get['db_host'],
|
||||
'db_port': int(get['db_port']),
|
||||
'db_user': get['db_user'],
|
||||
'db_password': get['db_password'],
|
||||
'db_type': get['type'],
|
||||
'ps': public.xssencode2(get['db_ps'].strip()),
|
||||
'addtime': int(time.time())
|
||||
}
|
||||
result = public.M("database_servers").insert(pdata)
|
||||
|
||||
if isinstance(result, int):
|
||||
public.WriteLog('Database manager', 'Add remote MySQL server[{}:{}]'.format(get['db_host'], get['db_port']))
|
||||
return public.return_message(0, 0, public.lang("Added successfully!"))
|
||||
return public.return_message(0, 0, public.lang("Add failed: {}", result))
|
||||
|
||||
def GetBaseCloudServer(self, get):
|
||||
'''
|
||||
@name 获取远程服务器列表
|
||||
@author hwliang<2021-01-10>
|
||||
@return list
|
||||
'''
|
||||
|
||||
# 解决get外多一层data
|
||||
if not get.get('type', None) and get.get('data', None):
|
||||
get['type'] = get['data'].get('type', '')
|
||||
where = '1=1'
|
||||
if 'type' in get: where = "db_type = '{}'".format(get['type'])
|
||||
|
||||
data = public.M('database_servers').where(where, ()).select()
|
||||
|
||||
if not isinstance(data, list): data = []
|
||||
|
||||
if get['type'] == 'mysql':
|
||||
bt_mysql_bin = public.get_mysql_info()['path'] + '/bin/mysql.exe'
|
||||
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': 'local server', 'addtime': 0, 'db_type': 'mysql'})
|
||||
elif get['type'] == 'sqlserver':
|
||||
pass
|
||||
elif get['type'] == 'mongodb':
|
||||
if os.path.exists('/www/server/mongodb/bin'):
|
||||
data.insert(0, {'id': 0, 'db_host': '127.0.0.1', 'db_port': 27017, 'db_user': 'root', 'db_password': '',
|
||||
'ps': 'local server', 'addtime': 0, 'db_type': 'mongodb'})
|
||||
elif get['type'] == 'redis':
|
||||
if os.path.exists('/www/server/redis'):
|
||||
data.insert(0, {'id': 0, 'db_host': '127.0.0.1', 'db_port': 6379, 'db_user': 'root', 'db_password': '',
|
||||
'ps': 'local server', 'addtime': 0, 'db_type': 'redis'})
|
||||
elif get['type'] == 'pgsql':
|
||||
if os.path.exists('/www/server/pgsql'):
|
||||
data.insert(0,
|
||||
{'id': 0, 'db_host': '127.0.0.1', 'db_port': 5432, 'db_user': 'postgres', 'db_password': '',
|
||||
'ps': 'local server', 'addtime': 0, 'db_type': 'pgsql'})
|
||||
return data
|
||||
|
||||
def RemoveBaseCloudServer(self, get):
|
||||
'''
|
||||
@name 删除远程服务器
|
||||
@author hwliang<2021-01-10>
|
||||
@param id<int> 远程服务器ID
|
||||
@return dict
|
||||
'''
|
||||
|
||||
id = int(get.id)
|
||||
if not id:
|
||||
return public.return_message(-1, 0, public.lang("Parameter passed error, please try again!"))
|
||||
db_find = public.M('database_servers').where('id=?', (id,)).find()
|
||||
if not db_find:
|
||||
return public.return_message(-1, 0, public.lang("The specified remote server does not exist!"))
|
||||
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 remote MySQL server [{}:{}]'.format(db_find['db_host'], int(db_find['db_port'])))
|
||||
return public.return_message(0, 0, public.lang("Successfully deleted!"))
|
||||
return public.return_message(0, 0, public.lang("Successfully deleted: {}", result))
|
||||
|
||||
def ModifyBaseCloudServer(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
|
||||
'''
|
||||
|
||||
arrs = ['db_host', 'db_port', 'db_user', 'db_password', 'db_ps', 'type']
|
||||
if get.type == 'redis':
|
||||
arrs = ['db_host', 'db_port', 'db_password', 'db_ps', 'type']
|
||||
|
||||
cRet = self.check_cloud_args(get, arrs)
|
||||
if isinstance(cRet, dict):
|
||||
return cRet
|
||||
|
||||
get['db_name'] = None
|
||||
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_message(-1, 0, public.lang("The specified remote server does not exist!"))
|
||||
_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_message(-1, 0,
|
||||
'The specified server already exists: [{}:{}]'.format(get['db_host'],
|
||||
get['db_port']))
|
||||
if db_find['db_user'] != get['db_user'] or db_find['db_password'] != get['db_password']:
|
||||
_modify = True
|
||||
_modify = True
|
||||
|
||||
if _modify:
|
||||
res = self.check_cloud_database(get)
|
||||
if isinstance(res, dict): return res
|
||||
pdata = {
|
||||
'db_host': get['db_host'],
|
||||
'db_port': int(get['db_port']),
|
||||
'db_user': get['db_user'],
|
||||
'db_password': get['db_password'],
|
||||
'db_type': get['type'],
|
||||
'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',
|
||||
'Modify the remote MySQL server[{}:{}]'.format(get['db_host'], get['db_port']))
|
||||
|
||||
return public.return_message(0, 0, public.lang("Successfully modified!"))
|
||||
return public.return_message(-1, 0, public.lang("Fail to edit: {}", result))
|
||||
|
||||
# 检测数据库执行错误
|
||||
def IsSqlError(self, mysqlMsg):
|
||||
|
||||
if mysqlMsg:
|
||||
mysqlMsg = str(mysqlMsg)
|
||||
if "MySQLdb" in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("MySQLdb component is missing!"))
|
||||
if "2002," in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("ERROR to connect database"))
|
||||
if "2003," in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"Database connection timed out, please check if the configuration is correct."))
|
||||
if "1045," in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("MySQL password error."))
|
||||
if "1040," in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"Exceeded maximum number of connections, please try again later."))
|
||||
if "1130," in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"Database connection failed, please check whether the root user is authorized to access 127.0.0.1."))
|
||||
if "using password:" in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("Database password is incorrect!"))
|
||||
if "Connection refused" in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("ERROR to connect database"))
|
||||
if "1133" in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("Database user does NOT exist!"))
|
||||
if "2005_login_error" == mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"The connection times out, please manually enable the TCP/IP function (Start Menu->SQL 2005->Configuration Tools->2005 Network Configuration->TCP/IP->Enable)"))
|
||||
if 'already exists' in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"The specified database already exists, please do not add it repeatedly."))
|
||||
if 'Cannot open backup device' in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang(
|
||||
"The operation failed, the remote database does not support the operation."))
|
||||
|
||||
if '1142' in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("Insufficient permissions, please use root user."))
|
||||
|
||||
if "DB-Lib error message 20018" in mysqlMsg:
|
||||
return public.return_message(-1, 0, public.lang("Create failed, SQL Server requires GUI support"))
|
||||
|
||||
return None
|
||||
|
||||
# ******************************************** 数据库公用方法 ******************************************/
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# get = {}
|
||||
# get['db_host'] = '192.168.1.37'
|
||||
# get['db_port'] = '3306'
|
||||
# get['db_user'] = 'root'
|
||||
|
||||
# get['db_password'] = 'HLANEMJFRbPE7Ny2'
|
||||
# get['db_ps'] = '2'
|
||||
# get['type'] = 'mysql'
|
||||
# bt = databaseBase()
|
||||
# ret = bt.AddCloudServer(get)
|
||||
# print(ret)
|
||||
|
||||
get = {}
|
||||
get['db_host'] = '192.168.66.73'
|
||||
get['db_port'] = '1433'
|
||||
get['db_user'] = 'sa'
|
||||
|
||||
get['db_password'] = 'dPYi6Gt8GC7SL58C'
|
||||
get['db_ps'] = '2'
|
||||
get['type'] = 'sqlserver'
|
||||
bt = databaseBase()
|
||||
ret = bt.get_test(get)
|
||||
print(ret)
|
||||
1556
class_v2/databaseModelV2/mongodbModel.py
Normal file
1556
class_v2/databaseModelV2/mongodbModel.py
Normal file
File diff suppressed because it is too large
Load Diff
1380
class_v2/databaseModelV2/pgsqlModel.py
Normal file
1380
class_v2/databaseModelV2/pgsqlModel.py
Normal file
File diff suppressed because it is too large
Load Diff
767
class_v2/databaseModelV2/redisModel.py
Normal file
767
class_v2/databaseModelV2/redisModel.py
Normal file
@@ -0,0 +1,767 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
# sqlite模型
|
||||
# ------------------------------
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
import public
|
||||
from databaseModelV2.base import databaseBase
|
||||
from public.validate import Param
|
||||
|
||||
try:
|
||||
import redis
|
||||
except:
|
||||
public.ExecShell("btpip install redis")
|
||||
import redis
|
||||
try:
|
||||
from YakPanel import session
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# 2025/6/6 同步国内
|
||||
|
||||
class panelRedisDB():
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 6379
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_CLOUD = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
self.error_message = ""
|
||||
|
||||
def redis_conn(self, db_idx=0):
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
if not os.path.exists('/www/server/redis'):
|
||||
return False
|
||||
if self.__config == "Config Error":
|
||||
return False
|
||||
|
||||
if not self.__DB_CLOUD:
|
||||
self.__DB_PASS = self.__config['requirepass']
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
|
||||
try:
|
||||
redis_pool = redis.ConnectionPool(
|
||||
host=self.__DB_HOST, port=self.__DB_PORT, password=self.__DB_PASS, db=db_idx
|
||||
)
|
||||
self.__DB_CONN = redis.Redis(connection_pool=redis_pool)
|
||||
self.__DB_CONN.ping()
|
||||
return self.__DB_CONN
|
||||
except redis.exceptions.ConnectionError:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = public.get_error_info()
|
||||
return False
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME:
|
||||
self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_CLOUD = 1
|
||||
return self
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
import ipaddress
|
||||
|
||||
result = {}
|
||||
redis_conf = public.readFile("{}/redis/redis.conf".format(public.get_setup_path()))
|
||||
|
||||
if not redis_conf:
|
||||
if not os.path.exists('/www/server/redis'):
|
||||
return False
|
||||
public.ExecShell("mv /www/server/redis/redis.conf /www/server/redis/redis.conf.bak")
|
||||
public.ExecShell(
|
||||
"wget -O /www/server/redis/redis.conf https://node.yakpanel.com/conf/redis.conf;chmod 600 /www/server/redis/redis.conf;chown redis:redis /www/server/redis/redis.conf"
|
||||
)
|
||||
time.sleep(1)
|
||||
redis_conf = public.readFile("{}/redis/redis.conf".format(public.get_setup_path()))
|
||||
|
||||
keys = ["bind", "port", "timeout", "maxclients", "databases", "requirepass", "maxmemory"]
|
||||
defaults = ["127.0.0.1", "6379", "300", "10000", "16", "", "0"]
|
||||
errors = []
|
||||
|
||||
for n, k in enumerate(keys):
|
||||
rep = r"\n{}\s+(.*)".format(k) # 更准确地捕获整行
|
||||
group = re.search(rep, redis_conf)
|
||||
if group:
|
||||
value = group.group(1).strip()
|
||||
try:
|
||||
if k == "maxmemory":
|
||||
# 将 maxmemory 从字节转换为兆字节并赋值
|
||||
value = str(int(value) // 1024 // 1024)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
value = defaults[n]
|
||||
|
||||
if k in ["port", "timeout", "maxclients", "databases", "maxmemory"]:
|
||||
if not value.isdigit():
|
||||
errors.append(f"'{k}' value must be a number, and the currently configured value is '{value}'")
|
||||
continue
|
||||
|
||||
if k == "bind":
|
||||
try:
|
||||
# 尝试解析IP地址以验证其格式
|
||||
ipaddress.ip_address(value)
|
||||
except ValueError:
|
||||
errors.append(
|
||||
f"'{k}' value must be a valid IP address, the current configuration value is '{value}'")
|
||||
continue
|
||||
|
||||
result[k] = value
|
||||
|
||||
if errors:
|
||||
error_message = "The following error was detected in the configuration file for the Redis database:\n" + "\n".join(
|
||||
errors)
|
||||
error_message += "\nPlease go to the software shop to make the correct changes to the configuration file of the redis plugin!"
|
||||
self.error_message = error_message
|
||||
return "Config Error"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class main(databaseBase):
|
||||
_DB_BACKUP_DIR = os.path.join(public.M("config").where("id=?", (1,)).getField("backup_path"), "database")
|
||||
_REDIS_BACKUP_DIR = os.path.join(_DB_BACKUP_DIR, "redis")
|
||||
_REDIS_CONF = os.path.join(public.get_setup_path(), "redis/redis.conf")
|
||||
|
||||
def __init__(self):
|
||||
if not os.path.exists(self._REDIS_BACKUP_DIR):
|
||||
os.makedirs(self._REDIS_BACKUP_DIR)
|
||||
|
||||
self._db_num = 16
|
||||
if os.path.exists(self._REDIS_CONF):
|
||||
redis_conf = public.readFile(self._REDIS_CONF)
|
||||
db_obj = re.search("\ndatabases\s+(\d+)", redis_conf)
|
||||
if db_obj:
|
||||
self._db_num = int(db_obj.group(1))
|
||||
|
||||
def GetCloudServer(self, args):
|
||||
"""
|
||||
@name 获取远程服务器列表
|
||||
@author hwliang<2021-01-10>
|
||||
@return list
|
||||
"""
|
||||
return public.return_message(0, 0, self.GetBaseCloudServer(args))
|
||||
|
||||
def AddCloudServer(self, args):
|
||||
"""
|
||||
@添加远程数据库
|
||||
"""
|
||||
# {"db_host":"192.168.66.129","db_port":"6379","db_user":"root","db_password":"password1","db_ps":"192.168.66.129","type":"redis"}
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
|
||||
Param('db_host').Require(),
|
||||
Param('db_port').Require().Number(">=", 1).Number("<=", 65535),
|
||||
Param('db_user').Require().String(),
|
||||
Param('db_password').Require().String(),
|
||||
Param('db_ps').Require().String(),
|
||||
Param('type').Require().String(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
return self.AddBaseCloudServer(args)
|
||||
|
||||
def RemoveCloudServer(self, args):
|
||||
"""
|
||||
@删除远程数据库
|
||||
"""
|
||||
return self.RemoveBaseCloudServer(args)
|
||||
|
||||
def ModifyCloudServer(self, args):
|
||||
"""
|
||||
@修改远程数据库
|
||||
"""
|
||||
return self.ModifyBaseCloudServer(args)
|
||||
|
||||
def get_obj_by_sid(self, sid: Union[int, str] = 0, conn_config: dict = None):
|
||||
"""
|
||||
@取mssql数据库对像 By sid
|
||||
@sid 数据库分类,0:本地
|
||||
"""
|
||||
if isinstance(sid, str):
|
||||
sid = int(sid)
|
||||
if sid != 0:
|
||||
if not conn_config: conn_config = public.M('database_servers').where("id=?", sid).find()
|
||||
db_obj = panelRedisDB()
|
||||
|
||||
try:
|
||||
db_obj = db_obj.set_host(
|
||||
conn_config['db_host'],
|
||||
conn_config['db_port'],
|
||||
None, conn_config['db_user'],
|
||||
conn_config['db_password']
|
||||
)
|
||||
except Exception as e:
|
||||
raise public.PanelError(e)
|
||||
else:
|
||||
db_obj = panelRedisDB()
|
||||
return db_obj
|
||||
|
||||
def local_xsssec(self, text):
|
||||
"""
|
||||
@name XSS防御,只替换关键字符,不转义字符
|
||||
@author hwliang
|
||||
@param text 要转义的字符
|
||||
@return str
|
||||
"""
|
||||
sub_list = {
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
}
|
||||
for s in sub_list.keys():
|
||||
text = text.replace(s, sub_list[s])
|
||||
return text
|
||||
|
||||
def get_list(self, args):
|
||||
"""
|
||||
@获取数据库列表
|
||||
@sql_type = redis
|
||||
"""
|
||||
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('sid').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
result = []
|
||||
sid = args.get('sid/d', 0)
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(0)
|
||||
if redis_obj is False:
|
||||
if panelRedisDB().error_message:
|
||||
return public.fail_v2(public.lang(str(panelRedisDB().error_message)))
|
||||
return public.success_v2(result)
|
||||
redis_info = redis_obj.info()
|
||||
is_cluster = redis_info.get("cluster_enabled", 0)
|
||||
if is_cluster != 0:
|
||||
return public.fail_v2(public.lang("not support redis cluster!"))
|
||||
db_num = self._db_num
|
||||
if sid != 0:
|
||||
db_num = 1000
|
||||
for x in range(0, db_num):
|
||||
|
||||
data = {}
|
||||
data['id'] = x
|
||||
data['name'] = 'DB{}'.format(x)
|
||||
|
||||
try:
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(x)
|
||||
|
||||
data['keynum'] = redis_obj.dbsize()
|
||||
result.append(data)
|
||||
except Exception as ex:
|
||||
break
|
||||
|
||||
return public.return_message(0, 0, result)
|
||||
|
||||
def set_redis_val(self, args):
|
||||
"""
|
||||
@设置或修改指定值
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('db_idx').Require().Integer(),
|
||||
Param('sid').Require().Integer(),
|
||||
Param('name').Require().String(), # 键
|
||||
Param('val').Require().String(), # 值
|
||||
Param('endtime').Integer(), # 过期时间
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
sid = args.get("sid/d", 0)
|
||||
db_idx = args.get("db_idx")
|
||||
name = args.get("name")
|
||||
val = args.get("val")
|
||||
endtime = args.get("endtime", None)
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(db_idx)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail!"))
|
||||
if endtime is not None:
|
||||
redis_obj.set(name, val, int(endtime))
|
||||
else:
|
||||
redis_obj.set(name, val)
|
||||
|
||||
public.set_module_logs('linux_redis', 'set_redis_val', 1)
|
||||
return public.return_message(0, 0, public.lang("Operation is successful"))
|
||||
|
||||
def del_redis_val(self, args):
|
||||
"""
|
||||
@删除key值
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
|
||||
Param('db_idx').Require().Integer(),
|
||||
Param('sid').Require().Integer(),
|
||||
Param('key').Require().String(), # 键
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
sid = args.get('sid/d', 0)
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(args.db_idx)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail!"))
|
||||
redis_obj.delete(args.key)
|
||||
|
||||
return public.return_message(0, 0, public.lang("Operation is successful"))
|
||||
|
||||
def clear_flushdb(self, args):
|
||||
"""
|
||||
清空数据库
|
||||
@ids 清空数据库列表,不传则清空所有
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
|
||||
Param('ids').String(), # "ids":"[0,1]"
|
||||
Param('sid').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
sid = args.get('sid/d', 0)
|
||||
ids = json.loads(args.ids)
|
||||
# ids = []
|
||||
if len(ids) == 0:
|
||||
for x in range(0, self._db_num):
|
||||
ids.append(x)
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(0)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail!"))
|
||||
for x in ids:
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(x)
|
||||
redis_obj.flushdb()
|
||||
|
||||
return public.return_message(0, 0, public.lang("Operation is successful"))
|
||||
|
||||
def get_db_keylist(self, args):
|
||||
"""
|
||||
@获取指定数据库key集合
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('db_type').Integer(),
|
||||
Param('db_idx').Require().Integer(),
|
||||
Param('limit').Integer(),
|
||||
Param('p').Integer(),
|
||||
Param('search').String(),
|
||||
Param('tojs').String(), # 不知道
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
search = '*'
|
||||
if 'search' in args: search = "*" + args.search + "*"
|
||||
db_idx = args.db_idx
|
||||
sid = args.get('sid/d', 0)
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(db_idx)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail!"))
|
||||
try:
|
||||
total = redis_obj.dbsize()
|
||||
except Exception as err:
|
||||
if str(err).find("Connection refused"):
|
||||
return public.fail_v2(
|
||||
public.lang(f"redis connection failed, please check if the database service is started!"))
|
||||
return public.fail_v2(
|
||||
public.lang(f"redis connection failed, please check if the database service is started!{err}"))
|
||||
info = {'p': 1, 'row': 20, 'count': total}
|
||||
|
||||
if hasattr(args, 'limit'): info['row'] = int(args.limit)
|
||||
if hasattr(args, 'p'): info['p'] = int(args['p'])
|
||||
|
||||
try:
|
||||
|
||||
if search != '*':
|
||||
keylist = redis_obj.keys(search)
|
||||
info['count'] = len(keylist)
|
||||
else:
|
||||
keys = redis_obj.scan(match="{}".format(search), count=info['p'] * info['row'])
|
||||
keylist = keys[1]
|
||||
except:
|
||||
keylist = []
|
||||
|
||||
info = {'p': 1, 'row': 10, 'count': len(keylist)}
|
||||
|
||||
if hasattr(args, 'limit'): info['row'] = int(args.limit)
|
||||
if hasattr(args, 'p'): info['p'] = int(args['p'])
|
||||
|
||||
import page
|
||||
# 实例化分页类
|
||||
page = page.Page()
|
||||
|
||||
info['uri'] = args
|
||||
info['return_js'] = ''
|
||||
if hasattr(args, 'tojs'):
|
||||
info['return_js'] = args.tojs
|
||||
|
||||
slist = keylist[(info['p'] - 1) * info['row']:info['p'] * info['row']]
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = page.GetPage(info, '1,2,3,4,5,8')
|
||||
rdata['where'] = ''
|
||||
rdata['data'] = []
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
idx = 0
|
||||
for key in slist:
|
||||
item = {}
|
||||
try:
|
||||
item['name'] = key.decode()
|
||||
except:
|
||||
item['name'] = str(key)
|
||||
|
||||
item['endtime'] = redis_obj.ttl(key)
|
||||
if item['endtime'] == -1:
|
||||
item['endtime'] = 0
|
||||
item['showtime'] = "royalty-free"
|
||||
else:
|
||||
key_ttl = redis_obj.ttl(key)
|
||||
INT_MAX = 2147483647
|
||||
INT_MIN = -2147483648
|
||||
if key_ttl > INT_MAX or key_ttl < INT_MIN:
|
||||
item['showtime'] = str(key_ttl) + "second"
|
||||
else:
|
||||
delta = timedelta(seconds=key_ttl)
|
||||
days, remainder = divmod(delta.total_seconds(), 86400)
|
||||
hours, remainder = divmod(remainder, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
formatted_ttl = f"{int(days)}days{int(hours)}hours{int(minutes)}min{int(seconds)}second"
|
||||
item['showtime'] = str(formatted_ttl)
|
||||
|
||||
item['type'] = redis_obj.type(key).decode()
|
||||
|
||||
if item['type'] == 'string':
|
||||
try:
|
||||
item['val'] = redis_obj.get(key).decode()
|
||||
except:
|
||||
item['val'] = str(redis_obj.get(key))
|
||||
elif item['type'] == 'hash':
|
||||
if redis_obj.hlen(key) > 500:
|
||||
item['val'] = "The amount of data is too large to display!Total {} entries".format(
|
||||
redis_obj.hlen(key))
|
||||
else:
|
||||
item['val'] = str(redis_obj.hgetall(key))
|
||||
elif item['type'] == 'list':
|
||||
if redis_obj.llen(key) > 500:
|
||||
item['val'] = "The amount of data is too large to display!Total {} entries".format(
|
||||
redis_obj.llen(key))
|
||||
else:
|
||||
item['val'] = str(redis_obj.lrange(key, 0, -1))
|
||||
elif item['type'] == 'set':
|
||||
if redis_obj.scard(key) > 500:
|
||||
item['val'] = "The amount of data is too large to display!Total {} entries".format(
|
||||
redis_obj.scard(key))
|
||||
else:
|
||||
item['val'] = str(redis_obj.smembers(key))
|
||||
elif item['type'] == 'zset':
|
||||
if redis_obj.zcard(key) > 500:
|
||||
item['val'] = "The amount of data is too large to display!Total {} entries".format(
|
||||
redis_obj.zcard(key))
|
||||
else:
|
||||
item['val'] = str(redis_obj.zrange(key, 0, -1, withscores=True))
|
||||
else:
|
||||
item['val'] = ''
|
||||
try:
|
||||
item['len'] = redis_obj.strlen(key)
|
||||
except:
|
||||
item['len'] = len(item['val'])
|
||||
item['val'] = self.local_xsssec(item['val'])
|
||||
item['name'] = public.xsssec(item['name'])
|
||||
rdata['data'].append(item)
|
||||
idx += 1
|
||||
return public.return_message(0, 0, rdata)
|
||||
|
||||
# 备份数据库
|
||||
def ToBackup(self, args):
|
||||
"""
|
||||
@备份数据库
|
||||
"""
|
||||
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('sid').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
sid = args.get('sid/d', 0)
|
||||
if sid != 0:
|
||||
return public.fail_v2(public.lang("Backing up remote databases is not supported at this time!"))
|
||||
|
||||
db_fidx = None
|
||||
if not hasattr(args, "db_idx"):
|
||||
db_fname = "all_db"
|
||||
else:
|
||||
db_fidx = args.db_idx
|
||||
db_fname = "db_{}".format(db_fidx)
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid)
|
||||
if redis_obj.redis_conn(0) is False:
|
||||
return public.fail_v2(public.lang("redis connect fail!"))
|
||||
|
||||
if db_fidx:
|
||||
redis_obj.redis_conn(0).execute_command("SELECT", int(db_fidx))
|
||||
redis_obj.redis_conn(0).execute_command("SAVE")
|
||||
else:
|
||||
for db_idx in range(0, self._db_num):
|
||||
redis_obj.redis_conn(db_idx).save()
|
||||
|
||||
redis_obj = redis_obj.redis_conn(0)
|
||||
src_path = os.path.join(redis_obj.config_get().get("dir", ""), "dump.rdb")
|
||||
if not os.path.exists(src_path):
|
||||
return public.fail_v2(public.lang('BACKUP_ERROR'))
|
||||
|
||||
file_name = "{db_fname}_{backup_time}_redis_data.rdb".format(db_fname=db_fname,
|
||||
backup_time=time.strftime("%Y-%m-%d_%H-%M-%S",
|
||||
time.localtime()))
|
||||
file_path = os.path.join(self._REDIS_BACKUP_DIR, file_name)
|
||||
|
||||
shutil.copyfile(src_path, file_path)
|
||||
if not os.path.exists(file_path):
|
||||
return public.fail_v2(public.lang('BACKUP_ERROR'))
|
||||
|
||||
return public.success_v2(public.lang('BACKUP_SUCCESS'))
|
||||
|
||||
def DelBackup(self, args):
|
||||
"""
|
||||
@删除备份文件
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('file').Require().SafePath(),
|
||||
# Param('sid').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
file = args.file
|
||||
if os.path.exists(file):
|
||||
os.remove(file)
|
||||
|
||||
return public.return_message(0, 0, public.lang("Delete successfully!"))
|
||||
|
||||
def InputSql(self, get):
|
||||
"""
|
||||
@导入数据库
|
||||
"""
|
||||
|
||||
# 校验参数
|
||||
try:
|
||||
get.validate([
|
||||
Param('file').Require().SafePath(),
|
||||
Param('sid').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
file = get.file
|
||||
sid = get.get('sid/d', 0)
|
||||
if not os.path.isfile(file):
|
||||
return public.fail_v2(public.lang("file not found"))
|
||||
|
||||
redis_obj = self.get_obj_by_sid(sid).redis_conn(0)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail"))
|
||||
|
||||
rpath = redis_obj.config_get()['dir']
|
||||
dst_path = '{}/dump.rdb'.format(rpath)
|
||||
public.ExecShell("/etc/init.d/redis stop")
|
||||
if os.path.exists(dst_path): os.remove(dst_path)
|
||||
shutil.copy2(file, dst_path)
|
||||
public.ExecShell("chown redis.redis {dump} && chmod 644 {dump}".format(dump=dst_path))
|
||||
public.ExecShell("/etc/init.d/redis start")
|
||||
if os.path.exists(dst_path):
|
||||
return public.return_message(0, 0, public.lang("Restore Successful."))
|
||||
return public.return_message(-1, 0, public.lang("Restore failure."))
|
||||
|
||||
def get_backup_list(self, get):
|
||||
"""
|
||||
@获取备份文件列表
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
get.validate([
|
||||
Param('search').String(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
def rd_file_info(f_path: str, arrs: list) -> dict:
|
||||
stat = os.stat(f_path)
|
||||
item = {
|
||||
'name': os.path.basename(f_path),
|
||||
'filepath': f_path,
|
||||
'size': stat.st_size,
|
||||
'mtime': int(stat.st_mtime),
|
||||
'sid': arrs[0],
|
||||
}
|
||||
try:
|
||||
if 0 <= int(arrs[0]) <= 15:
|
||||
item['conn_config'] = cloud_list['id-' + str(arrs[0])]
|
||||
except ValueError:
|
||||
pass
|
||||
return item
|
||||
|
||||
search = ''
|
||||
if hasattr(get, 'search'):
|
||||
search = get['search'].strip().lower()
|
||||
|
||||
nlist = []
|
||||
cloud_list = {}
|
||||
for x in self.GetCloudServer({'type': 'redis'}).get("message", []):
|
||||
cloud_list['id-' + str(x['id'])] = x
|
||||
|
||||
for name in os.listdir(self._REDIS_BACKUP_DIR):
|
||||
if search:
|
||||
if name.lower().find(search) == -1: continue
|
||||
|
||||
file_path = os.path.join(self._REDIS_BACKUP_DIR, name).replace('//', '/')
|
||||
|
||||
if os.path.isdir(file_path):
|
||||
for f in os.listdir(file_path):
|
||||
f_path = os.path.join(file_path, f).replace('//', '/')
|
||||
if os.path.isfile(f_path):
|
||||
nlist.append(
|
||||
rd_file_info(f_path, f.split('_'))
|
||||
)
|
||||
elif os.path.isfile(file_path):
|
||||
nlist.append(
|
||||
rd_file_info(file_path, name.split('_'))
|
||||
)
|
||||
else:
|
||||
continue
|
||||
|
||||
if hasattr(get, 'sort'):
|
||||
nlist = sorted(nlist, key=lambda data: data['mtime'], reverse=get["sort"] == "desc")
|
||||
|
||||
return public.return_message(0, 0, nlist)
|
||||
|
||||
def restart_services(self):
|
||||
"""
|
||||
@重启服务
|
||||
"""
|
||||
public.ExecShell('net stop redis')
|
||||
public.ExecShell('net start redis')
|
||||
return True
|
||||
|
||||
def check_cloud_database_status(self, conn_config):
|
||||
"""
|
||||
@检测远程数据库是否连接
|
||||
@conn_config 远程数据库配置,包含host port pwd等信息
|
||||
"""
|
||||
try:
|
||||
|
||||
sql_obj = panelRedisDB().set_host(conn_config['db_host'], conn_config['db_port'], conn_config['db_name'],
|
||||
conn_config['db_user'], conn_config['db_password'])
|
||||
redis_obj = sql_obj.redis_conn(0)
|
||||
if redis_obj is False:
|
||||
return public.fail_v2(public.lang("redis connect fail"))
|
||||
keynum = redis_obj.dbsize()
|
||||
return True
|
||||
except Exception as ex:
|
||||
return public.fail_v2(public.lang("remote database connect fail {}".format(ex)))
|
||||
|
||||
# 数据库状态检测
|
||||
def CheckDatabaseStatus(self, get):
|
||||
"""
|
||||
数据库状态检测
|
||||
"""
|
||||
if not hasattr(get, "sid"):
|
||||
return public.fail_v2("params not found! sid")
|
||||
if not str(get.sid).isdigit():
|
||||
return public.fail_v2("params not found! sid")
|
||||
sid = int(get.sid)
|
||||
|
||||
if sid != 0:
|
||||
conn_config = public.M("database_servers").where("id=? AND LOWER(db_type)=LOWER('redis')",
|
||||
(sid,)).find()
|
||||
if not conn_config:
|
||||
return public.fail_v2(public.lang("Remote database information does not exist!"))
|
||||
conn_config["db_name"] = None
|
||||
redis_obj = panelRedisDB().set_host(conn_config['db_host'], conn_config['db_port'],
|
||||
conn_config.get("db_name"), conn_config['db_user'],
|
||||
conn_config['db_password'])
|
||||
else:
|
||||
redis_obj = panelRedisDB()
|
||||
if redis_obj.redis_conn(0) is False:
|
||||
return {"status": True, "msg": "exceptions", "db_status": False}
|
||||
try:
|
||||
redis_obj.redis_conn(0).dbsize()
|
||||
db_status = True
|
||||
except:
|
||||
db_status = False
|
||||
return {"status": True, "msg": "normalcy" if db_status is True else "exceptions", "db_status": db_status}
|
||||
22
class_v2/databaseModelV2/sqliteModel.py
Normal file
22
class_v2/databaseModelV2/sqliteModel.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# sqlite模型
|
||||
#------------------------------
|
||||
import os,sys,re,json,shutil,psutil,time
|
||||
from databaseModelV2.base import databaseBase
|
||||
import public
|
||||
|
||||
|
||||
class main(databaseBase):
|
||||
|
||||
def get_list(self,args):
|
||||
|
||||
return []
|
||||
667
class_v2/databaseModelV2/sqlserverModel.py
Normal file
667
class_v2/databaseModelV2/sqlserverModel.py
Normal file
@@ -0,0 +1,667 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# sqlite模型
|
||||
#------------------------------
|
||||
import os,re,json,time
|
||||
from databaseModelV2.base import databaseBase
|
||||
|
||||
|
||||
# import public,panelMssql
|
||||
import public
|
||||
import panel_mssql_v2 as panelMssql
|
||||
|
||||
|
||||
from public.validate import Param
|
||||
try:
|
||||
from YakPanel import session
|
||||
except :pass
|
||||
|
||||
|
||||
class main(databaseBase):
|
||||
|
||||
def get_list(self,args):
|
||||
"""
|
||||
@获取数据库列表
|
||||
@sql_type = sqlserver
|
||||
"""
|
||||
# {"table":"databases","search":"","limit":"10","p":1,"order":"username desc"}
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('table').Require().String(),
|
||||
Param('search').String(),
|
||||
Param('order').String(),
|
||||
Param('limit').Integer(),
|
||||
Param('p').Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
# return self.get_base_list(args, sql_type = 'sqlserver')
|
||||
return public.return_message(0, 0, self.get_base_list(args, sql_type = 'sqlserver'))
|
||||
|
||||
|
||||
def get_mssql_obj_by_sid(self,sid = 0,conn_config = None):
|
||||
"""
|
||||
@取mssql数据库对像 By sid
|
||||
@sid 数据库分类,0:本地
|
||||
"""
|
||||
if type(sid) == str:
|
||||
try:
|
||||
sid = int(sid)
|
||||
except :sid = 0
|
||||
|
||||
if sid:
|
||||
if not conn_config: conn_config = public.M('database_servers').where("id=?" ,sid).find()
|
||||
db_obj = panelMssql.panelMssql()
|
||||
|
||||
try:
|
||||
db_obj = db_obj.set_host(conn_config['db_host'],conn_config['db_port'],None,conn_config['db_user'],conn_config['db_password'])
|
||||
except Exception as e:
|
||||
raise public.PanelError(e)
|
||||
else:
|
||||
db_obj = panelMssql.panelMssql()
|
||||
return db_obj
|
||||
|
||||
def get_mssql_obj(self,db_name):
|
||||
"""
|
||||
@取mssql数据库对象
|
||||
@db_name 数据库名称
|
||||
"""
|
||||
is_cloud_db = False
|
||||
if db_name:
|
||||
db_find = public.M('databases').where("name=?" ,db_name).find()
|
||||
if db_find['sid']:
|
||||
return self.get_mssql_obj_by_sid(db_find['sid'])
|
||||
is_cloud_db = db_find['db_type'] in ['1',1]
|
||||
|
||||
if is_cloud_db:
|
||||
|
||||
db_obj = panelMssql.panelMssql()
|
||||
conn_config = json.loads(db_find['conn_config'])
|
||||
try:
|
||||
db_obj = db_obj.set_host(conn_config['db_host'],conn_config['db_port'],conn_config['db_name'],conn_config['db_user'],conn_config['db_password'])
|
||||
except Exception as e:
|
||||
raise public.PanelError(e)
|
||||
else:
|
||||
db_obj = panelMssql.panelMssql()
|
||||
return db_obj
|
||||
|
||||
def GetCloudServer(self,args):
|
||||
'''
|
||||
@name 获取远程服务器列表
|
||||
@author hwliang<2021-01-10>
|
||||
@return list
|
||||
'''
|
||||
# {"type":"sqlserver"}
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
|
||||
Param('type').Require().String('in', ['sqlserver']),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
# return self.GetBaseCloudServer(args)
|
||||
return public.return_message(0, 0, self.GetBaseCloudServer(args))
|
||||
|
||||
|
||||
def AddCloudServer(self,args):
|
||||
'''
|
||||
@添加远程数据库
|
||||
'''
|
||||
|
||||
return self.AddBaseCloudServer(args)
|
||||
# return public.return_message(0, 0, self.AddBaseCloudServer(args))
|
||||
|
||||
def RemoveCloudServer(self,args):
|
||||
'''
|
||||
@删除远程数据库
|
||||
'''
|
||||
return self.RemoveBaseCloudServer(args)
|
||||
# return public.return_message(0, 0, self.RemoveBaseCloudServer(args))
|
||||
|
||||
def ModifyCloudServer(self,args):
|
||||
'''
|
||||
@修改远程数据库
|
||||
'''
|
||||
return self.ModifyBaseCloudServer(args)
|
||||
# return public.return_message(0, 0, self.ModifyBaseCloudServer(args))
|
||||
|
||||
def AddDatabase(self,args):
|
||||
"""
|
||||
@添加数据库
|
||||
"""
|
||||
# {"name":"test1","db_user":"test1","password":"nnMCp2ccJcBahJec","sid":"3","active":true,"ps":"test1","ssl":"REQUIRE SSL"}
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('name').Require().String(),
|
||||
Param('db_user').Require().String(),
|
||||
Param('password').Require().String(),
|
||||
Param('sid').Require().Integer(),
|
||||
Param('active').Require().Bool(),
|
||||
Param('ps').String(),
|
||||
Param('ssl').String(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
|
||||
try:
|
||||
res = self.add_base_database(args)
|
||||
if not res['status']:
|
||||
# return res
|
||||
return public.return_message(-1, 0, res['msg'])
|
||||
|
||||
data_name = res['data_name']
|
||||
username = res['username']
|
||||
password = res['data_pwd']
|
||||
|
||||
if re.match(r"^\d+",data_name):
|
||||
# return public.returnMsg(False, public.lang("SQLServer databases cannot start with numbers!"))
|
||||
return public.return_message(-1, 0, public.lang("SQLServer databases cannot start with numbers!"))
|
||||
|
||||
reg_count = 0
|
||||
regs = ['[a-z]','[A-Z]',r'\W','[0-9]']
|
||||
for x in regs:
|
||||
if re.search(x,password): reg_count += 1
|
||||
|
||||
if len(password) < 8 or len(password) >128 or reg_count < 3 :
|
||||
# return public.returnMsg(False, public.lang("SQLServer password complexity policy does not match, should be 8-128 characters, and contain any 3 of them in upper case, lower case, digits, special symbols!"))
|
||||
return public.return_message(-1, 0, 'SQLServer password complexity policy does not match, should be 8-128 '
|
||||
'characters, and contain any 3 of them in upper case, lower case, '
|
||||
'digits, special symbols!')
|
||||
|
||||
try:
|
||||
self.sid = int(args['sid'])
|
||||
except :
|
||||
self.sid = 0
|
||||
|
||||
dtype = 'SQLServer'
|
||||
#添加SQLServer
|
||||
mssql_obj = self.get_mssql_obj_by_sid(self.sid)
|
||||
result = mssql_obj.execute("CREATE DATABASE %s" % data_name)
|
||||
isError = self.IsSqlError(result)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
|
||||
mssql_obj.execute("DROP LOGIN %s" % username)
|
||||
|
||||
#添加用户
|
||||
self.__CreateUsers(data_name,username,password,'127.0.0.1')
|
||||
|
||||
if not hasattr(args,'ps'): args['ps'] = public.getMsg('INPUT_PS');
|
||||
addTime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
|
||||
pid = 0
|
||||
if hasattr(args,'pid'): pid = args.pid
|
||||
|
||||
if hasattr(args,'contact'):
|
||||
site = public.M('sites').where("id=?",(args.contact,)).field('id,name').find()
|
||||
if site:
|
||||
pid = int(args.contact)
|
||||
args['ps'] = site['name']
|
||||
|
||||
db_type = 0
|
||||
if self.sid: db_type = 2
|
||||
|
||||
public.set_module_logs('linux_sqlserver','AddDatabase',1)
|
||||
#添加入SQLITE
|
||||
public.M('databases').add('pid,sid,db_type,name,username,password,accept,ps,addtime,type',(pid,self.sid,db_type,data_name,username,password,'127.0.0.1',args['ps'],addTime,dtype))
|
||||
public.WriteLog("TYPE_DATABASE", 'DATABASE_ADD_SUCCESS',(data_name,))
|
||||
# return public.returnMsg(True, public.lang("Added successfully!"))
|
||||
return public.return_message(0, 0, public.lang("Added successfully!"))
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
def DeleteDatabase(self,args):
|
||||
"""
|
||||
@删除数据库
|
||||
"""
|
||||
# {"id":128,"name":"失去了23"}
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('name').Require().String(),
|
||||
Param('id').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
id = args['id']
|
||||
find = public.M('databases').where("id=?",(id,)).field('id,pid,name,username,password,type,accept,ps,addtime,sid,db_type').find();
|
||||
if not find:
|
||||
# return public.returnMsg(False, public.lang("The specified database does not exist."))
|
||||
return public.return_message(-1, 0, public.lang("The specified database does not exist."))
|
||||
|
||||
name = args['name']
|
||||
username = find['username']
|
||||
|
||||
mssql_obj = self.get_mssql_obj_by_sid(find['sid'])
|
||||
mssql_obj.execute("ALTER DATABASE %s SET SINGLE_USER with ROLLBACK IMMEDIATE" % name)
|
||||
result = mssql_obj.execute("DROP DATABASE %s" % name)
|
||||
|
||||
if self.get_database_size_by_id(find['sid']):
|
||||
isError = self.IsSqlError(result)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
|
||||
mssql_obj.execute("DROP LOGIN %s" % username)
|
||||
|
||||
#删除SQLITE
|
||||
public.M('databases').where("id=?",(id,)).delete()
|
||||
public.WriteLog("TYPE_DATABASE", 'DATABASE_DEL_SUCCESS',(name,))
|
||||
# return public.returnMsg(True, public.lang("Delete successfully!"))
|
||||
return public.return_message(0, 0, public.lang("Delete successfully!"))
|
||||
|
||||
|
||||
|
||||
def ToBackup(self,args):
|
||||
"""
|
||||
@备份数据库 id 数据库id
|
||||
"""
|
||||
|
||||
|
||||
id = args['id']
|
||||
find = public.M('databases').where("id=?",(id,)).find()
|
||||
if not find:
|
||||
# return public.returnMsg(False, public.lang("Database does not exist!"))
|
||||
return public.return_message(-1, 0, public.lang("Database does not exist!"))
|
||||
|
||||
self.CheckBackupPath(args)
|
||||
|
||||
fileName = find['name'] + '_' + time.strftime('%Y%m%d_%H%M%S',time.localtime()) + '.bak'
|
||||
backupName = session['config']['backup_path'] + '/database/sqlserver/' + fileName
|
||||
|
||||
mssql_obj = self.get_mssql_obj_by_sid(find['sid'])
|
||||
|
||||
if not int(find['sid']):
|
||||
ret = mssql_obj.execute("backup database %s To disk='%s'" % (find['name'],backupName))
|
||||
isError=self.IsSqlError(ret)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
else:
|
||||
#远程数据库
|
||||
# return public.returnMsg(False, public.lang("Operation failed. Remote database cannot be backed up."))
|
||||
return public.return_message(-1, 0, public.lang("Operation failed. Remote database cannot be backed up."))
|
||||
|
||||
if not os.path.exists(backupName):
|
||||
# return public.returnMsg(False, public.lang("Backup error"))
|
||||
return public.return_message(-1, 0, public.lang("Backup error"))
|
||||
|
||||
public.M('backup').add('type,name,pid,filename,size,addtime',(1,fileName,id,backupName,0,time.strftime('%Y-%m-%d %X',time.localtime())))
|
||||
public.WriteLog("TYPE_DATABASE", "DATABASE_BACKUP_SUCCESS",(find['name'],))
|
||||
|
||||
if os.path.getsize(backupName) < 2048:
|
||||
# return public.returnMsg(True, public.lang("The backup file size is smaller than 2Kb. Check the backup integrity."))
|
||||
return public.return_message(0, 0, public.lang("The backup file size is smaller than 2Kb. Check the backup integrity."))
|
||||
else:
|
||||
# return public.returnMsg(True, public.lang("Backup Succeeded!"))
|
||||
return public.return_message(0, 0, public.lang("Backup Succeeded!"))
|
||||
|
||||
def DelBackup(self,args):
|
||||
"""
|
||||
@删除备份文件
|
||||
"""
|
||||
return self.delete_base_backup(args)
|
||||
# return public.return_message(0, 0, self.delete_base_backup(args))
|
||||
|
||||
|
||||
#导入
|
||||
def InputSql(self,get):
|
||||
# 校验参数
|
||||
try:
|
||||
get.validate([
|
||||
Param('file').SafePath(), # 文件路径
|
||||
Param('name').String(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
name = get.name
|
||||
file = get.file
|
||||
|
||||
find = public.M('databases').where("name=?",(name,)).find()
|
||||
if not find:
|
||||
# return public.returnMsg(False, public.lang("Database does not exist!"))
|
||||
return public.return_message(-1, 0, public.lang("Database does not exist!"))
|
||||
|
||||
tmp = file.split('.')
|
||||
exts = ['sql','zip','bak']
|
||||
ext = tmp[len(tmp) -1]
|
||||
if ext not in exts:
|
||||
# return public.returnMsg(False, public.lang("DATABASE_INPUT_ERR_FORMAT"))
|
||||
return public.return_message(-1, 0, public.lang("Select sql、gz、zip file!"))
|
||||
|
||||
backupPath = session['config']['backup_path'] + '/database'
|
||||
|
||||
if ext == 'zip':
|
||||
try:
|
||||
fname = os.path.basename(file).replace('.zip','')
|
||||
dst_path = backupPath + '/' +fname
|
||||
if not os.path.exists(dst_path): os.makedirs(dst_path)
|
||||
|
||||
public.unzip(file,dst_path)
|
||||
for x in os.listdir(dst_path):
|
||||
if x.find('bak') >= 0 or x.find('sql') >= 0:
|
||||
file = dst_path + '/' + x
|
||||
break
|
||||
except :
|
||||
# return public.returnMsg(False, public.lang("The import failed because the file is not a valid ZIP file."))
|
||||
return public.return_message(-1, 0, public.lang("The import failed because the file is not a valid ZIP file."))
|
||||
|
||||
mssql_obj = self.get_mssql_obj_by_sid(find['sid'])
|
||||
data = mssql_obj.query("use %s ;select filename from sysfiles" % find['name'])
|
||||
|
||||
isError = self.IsSqlError(data)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
if type(data) == str:
|
||||
# return public.returnMsg(False,data)
|
||||
return public.return_message(-1, 0, data)
|
||||
|
||||
mssql_obj.execute("ALTER DATABASE %s SET OFFLINE WITH ROLLBACK IMMEDIATE" % (find['name']))
|
||||
mssql_obj.execute("use master;restore database %s from disk='%s' with replace, MOVE N'%s' TO N'%s',MOVE N'%s_Log' TO N'%s' " % (find['name'],file,find['name'],data[0][0],find['name'],data[1][0]))
|
||||
mssql_obj.execute("ALTER DATABASE %s SET ONLINE" % (find['name']))
|
||||
|
||||
public.WriteLog("TYPE_DATABASE", 'Description Succeeded in importing database [{}]'.format(name))
|
||||
# return public.returnMsg(True, public.lang("DATABASE_INPUT_SUCCESS"))
|
||||
return public.return_message(0, 0, public.lang("Successfully imported database!"))
|
||||
|
||||
|
||||
#同步数据库到服务器
|
||||
def SyncToDatabases(self,get):
|
||||
|
||||
# 校验?
|
||||
|
||||
type = int(get['type'])
|
||||
n = 0
|
||||
sql = public.M('databases')
|
||||
if type == 0:
|
||||
data = sql.field('id,name,username,password,accept,type,sid,db_type').where('type=?',('SQLServer',)).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,name,username,password,sid,db_type,accept,type').find()
|
||||
result = self.ToDataBase(find)
|
||||
if result == 1: n +=1
|
||||
|
||||
if n == 1:
|
||||
# return public.returnMsg(True, public.lang("Synchronization succeeded"))
|
||||
return public.return_message(0, 0, public.lang("Synchronization succeeded"))
|
||||
|
||||
elif n == 0:
|
||||
# return public.returnMsg(False, public.lang("Sync failed"))
|
||||
return public.return_message(-1, 0, public.lang("Sync failed"))
|
||||
|
||||
# return public.returnMsg(True,'Database sync success',(str(n),))
|
||||
return public.return_message(0, 0, public.lang("Database sync success", str(n)))
|
||||
|
||||
#添加到服务器
|
||||
def ToDataBase(self,find):
|
||||
|
||||
if find['username'] == 'bt_default':
|
||||
# return 0
|
||||
return public.return_message(0, 0, 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']
|
||||
mssql_obj = self.get_mssql_obj_by_sid(self.sid)
|
||||
result = mssql_obj.execute("CREATE DATABASE %s" % find['name'])
|
||||
isError = self.IsSqlError(result)
|
||||
if isError != None and not 'already exists' in result:
|
||||
# return -1
|
||||
return public.return_message(0, 0, -1)
|
||||
|
||||
self.__CreateUsers(find['name'],find['username'],find['password'],'127.0.0.1')
|
||||
|
||||
# return 1
|
||||
return public.return_message(0, 0, 1)
|
||||
|
||||
|
||||
#从服务器获取数据库
|
||||
def SyncGetDatabases(self,get):
|
||||
|
||||
n = 0
|
||||
s = 0
|
||||
db_type = 0
|
||||
self.sid = get.get('sid/d',0)
|
||||
if self.sid: db_type = 2
|
||||
|
||||
mssql_obj = self.get_mssql_obj_by_sid(self.sid)
|
||||
|
||||
data = mssql_obj.query('SELECT name FROM MASTER.DBO.SYSDATABASES ORDER BY name')
|
||||
isError = self.IsSqlError(data)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
if type(data) == str:
|
||||
# return public.returnMsg(False,data)
|
||||
return public.return_message(-1, 0, data)
|
||||
|
||||
sql = public.M('databases')
|
||||
nameArr = ['information_schema','performance_schema','mysql','sys','master','model','msdb','tempdb','ReportServerTempDB','YueMiao','ReportServer']
|
||||
for item in data:
|
||||
dbname = item[0]
|
||||
if sql.where("name=?",(dbname,)).count(): continue
|
||||
if not dbname in nameArr:
|
||||
if sql.table('databases').add('name,username,password,accept,ps,addtime,type,sid,db_type',(dbname,dbname,'','',public.getMsg('INPUT_PS'),time.strftime('%Y-%m-%d %X',time.localtime()),'SQLServer',self.sid,db_type)): n +=1
|
||||
|
||||
# return public.returnMsg(True,'Database success',(str(n),))
|
||||
return public.return_message(0, 0, public.lang("Database success", n))
|
||||
|
||||
def ResDatabasePassword(self,args):
|
||||
"""
|
||||
@修改用户密码
|
||||
"""
|
||||
# 校验参数
|
||||
try:
|
||||
args.validate([
|
||||
Param('password').Require().String(),
|
||||
Param('name').Require().String(),
|
||||
Param('id').Require().Integer(),
|
||||
], [
|
||||
public.validate.trim_filter(),
|
||||
])
|
||||
except Exception as ex:
|
||||
public.print_log("error info: {}".format(ex))
|
||||
return public.return_message(-1, 0, str(ex))
|
||||
|
||||
|
||||
id = args['id']
|
||||
username = args['name'].strip()
|
||||
newpassword = public.trim(args['password'])
|
||||
|
||||
try:
|
||||
# if not newpassword:
|
||||
# return public.returnMsg(False, public.lang("The password of database [' + username + '] cannot be empty."))
|
||||
if len(re.search(r"^[\w@\.]+$", newpassword).groups()) > 0:
|
||||
# return public.returnMsg(False, public.lang("The database password cannot be empty or contain special characters"))
|
||||
return public.return_message(-1, 0, public.lang("The database password cannot be empty or contain special characters"))
|
||||
except :
|
||||
# return public.returnMsg(False, public.lang("The database password cannot be empty or contain special characters"))
|
||||
return public.return_message(-1, 0, public.lang("The database password cannot be empty or contain special characters"))
|
||||
|
||||
find = public.M('databases').where("id=?",(id,)).field('id,pid,name,username,password,type,accept,ps,addtime,sid').find()
|
||||
if not find:
|
||||
# return public.returnMsg(False, public.lang("Modify the failure,The specified database does not exist."));
|
||||
return public.return_message(-1, 0, public.lang("Modify the failure,The specified database does not exist."))
|
||||
|
||||
mssql_obj = self.get_mssql_obj_by_sid(find['sid'])
|
||||
mssql_obj.execute("EXEC sp_password NULL, '%s', '%s'" % (newpassword,username))
|
||||
|
||||
#修改SQLITE
|
||||
public.M('databases').where("id=?",(id,)).setField('password',newpassword)
|
||||
|
||||
public.WriteLog("TYPE_DATABASE",'Database password success',(find['name'],))
|
||||
# return public.returnMsg(True, 'Database password success',(find['name'],))
|
||||
return public.return_message(0, 0, public.lang("Database password success", find['name']))
|
||||
|
||||
|
||||
def get_root_pwd(self,args):
|
||||
"""
|
||||
@获取sa密码
|
||||
"""
|
||||
mssql_obj = panelMssql.panelMssql()
|
||||
ret = mssql_obj.get_sql_name()
|
||||
if not ret : return public.returnMsg(False, public.lang("The SQL Server is not installed or started. Install or start it first"))
|
||||
|
||||
sa_path = '{}/data/sa.pl'.format(public.get_panel_path())
|
||||
if os.path.exists(sa_path):
|
||||
password = public.readFile(sa_path)
|
||||
return public.returnMsg(True,password)
|
||||
return public.returnMsg(True, public.lang(""))
|
||||
|
||||
|
||||
def set_root_pwd(self,args):
|
||||
"""
|
||||
@设置sa密码
|
||||
"""
|
||||
password = public.trim(args['password'])
|
||||
try:
|
||||
if not password:
|
||||
return public.returnMsg(False, public.lang("The password of database [' + username + '] cannot be empty."))
|
||||
if len(re.search(r"^[\w@\.]+$", password).groups()) > 0:
|
||||
return public.returnMsg(False, public.lang("saThe password cannot be empty or have special symbols"))
|
||||
except :
|
||||
return public.returnMsg(False, public.lang("saThe password cannot be empty or have special symbols"))
|
||||
|
||||
mssql_obj = panelMssql.panelMssql()
|
||||
result = mssql_obj.execute("EXEC sp_password NULL, '%s', 'sa'" % password)
|
||||
|
||||
isError = self.IsSqlError(result)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
|
||||
public.writeFile('data/sa.pl',password)
|
||||
session['config']['mssql_sa'] = password
|
||||
return public.returnMsg(True, public.lang("The password of sa is changed successfully."))
|
||||
|
||||
|
||||
|
||||
def get_database_size_by_id(self,args):
|
||||
"""
|
||||
@获取数据库尺寸(批量删除验证)
|
||||
@args json/int 数据库id
|
||||
"""
|
||||
total = 0
|
||||
db_id = args
|
||||
if not isinstance(args,int): db_id = args['db_id']
|
||||
|
||||
try:
|
||||
name = public.M('databases').where('id=?',db_id).getField('name')
|
||||
mssql_obj = self.get_mssql_obj(name)
|
||||
tables = mssql_obj.query("select name,size,type from sys.master_files where type=0 and name = '{}'".format(name))
|
||||
|
||||
total = tables[0][1]
|
||||
if not total: total = 0
|
||||
except :pass
|
||||
|
||||
return total
|
||||
|
||||
def check_del_data(self,args):
|
||||
"""
|
||||
@删除数据库前置检测
|
||||
"""
|
||||
# {"ids": "[128]"}
|
||||
|
||||
# return self.check_base_del_data(args)
|
||||
return public.return_message(0, 0, self.check_base_del_data(args))
|
||||
|
||||
#本地创建数据库
|
||||
def __CreateUsers(self,data_name,username,password,address):
|
||||
"""
|
||||
@创建数据库用户
|
||||
"""
|
||||
mssql_obj = self.get_mssql_obj_by_sid(self.sid)
|
||||
mssql_obj.execute("use %s create login %s with password ='%s' , default_database = %s" % (data_name,username,password,data_name))
|
||||
mssql_obj.execute("use %s create user %s for login %s with default_schema=dbo" % (data_name,username,username))
|
||||
mssql_obj.execute("use %s exec sp_addrolemember 'db_owner','%s'" % (data_name,data_name))
|
||||
mssql_obj.execute("ALTER DATABASE %s SET MULTI_USER" % data_name)
|
||||
|
||||
|
||||
#检测备份目录并赋值权限(MSSQL需要Authenticated Users)
|
||||
def CheckBackupPath(self,get):
|
||||
backupFile = session['config']['backup_path'] + '/database/sqlserver'
|
||||
if not os.path.exists(backupFile):
|
||||
os.makedirs(backupFile)
|
||||
get.filename = backupFile
|
||||
get.user = 'Authenticated Users'
|
||||
get.access = 2032127
|
||||
import files
|
||||
files.files().SetFileAccess(get)
|
||||
|
||||
def check_cloud_database_status(self,conn_config):
|
||||
"""
|
||||
@检测远程数据库是否连接
|
||||
@conn_config 远程数据库配置,包含host port pwd等信息
|
||||
"""
|
||||
try:
|
||||
|
||||
import panelMssql
|
||||
if not 'db_name' in conn_config: conn_config['db_name'] = None
|
||||
sql_obj = panelMssql.panelMssql().set_host(conn_config['db_host'],conn_config['db_port'],conn_config['db_name'],conn_config['db_user'],conn_config['db_password'])
|
||||
data = sql_obj.query("SELECT name FROM MASTER.DBO.SYSDATABASES ORDER BY name")
|
||||
|
||||
isError = self.IsSqlError(data)
|
||||
if isError != None:
|
||||
return isError
|
||||
# return public.return_message(-1, 0, isError)
|
||||
if type(data) == str:
|
||||
# return public.returnMsg(False,data)
|
||||
return public.return_message(-1, 0, data)
|
||||
|
||||
if not conn_config['db_name']:
|
||||
# return True
|
||||
return public.return_message(0, 0, True)
|
||||
for i in data:
|
||||
if i[0] == conn_config['db_name']:
|
||||
# return True
|
||||
return public.return_message(0, 0, True)
|
||||
# return public.returnMsg(False, public.lang("The specified database does not exist!"))
|
||||
return public.return_message(-1, 0, public.lang("The specified database does not exist!"))
|
||||
except Exception as ex:
|
||||
|
||||
# return public.returnMsg(False,ex)
|
||||
return public.return_message(-1, 0, ex)
|
||||
Reference in New Issue
Block a user