Merge pull request #518 from midoks/dev

mariadb功能增强
pull/543/head
Mr Chen 1 year ago committed by GitHub
commit e33bdc5b7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      class/core/config_api.py
  2. 17
      class/core/system_api.py
  3. 1
      plugins/mariadb/index.html
  4. 235
      plugins/mariadb/index.py
  5. 186
      plugins/mariadb/index_mariadb.py
  6. 279
      plugins/mariadb/js/mariadb.js
  7. 2
      plugins/mariadb/versions/10.11/install.sh
  8. 2
      plugins/mariadb/versions/10.6/install.sh
  9. 2
      plugins/mariadb/versions/10.9/install.sh
  10. 2
      plugins/mariadb/versions/11.0/install.sh
  11. 2
      plugins/mariadb/versions/11.1/install.sh
  12. 2
      plugins/mariadb/versions/11.2/install.sh
  13. 2
      plugins/mariadb/versions/11.3/install.sh
  14. 108
      plugins/mysql-apt/conf/my8.2.cnf
  15. 2
      plugins/mysql-apt/info.json
  16. 140
      plugins/mysql-apt/versions/8.2/install.sh
  17. 130
      plugins/mysql/index.py
  18. 46
      plugins/mysql/js/mysql.js
  19. 2
      plugins/php-apt/info.json
  20. 49
      plugins/php-apt/versions/83/install.sh
  21. 73
      plugins/php-apt/versions/phplib.conf
  22. 163
      route/static/app/index.js
  23. 2
      route/static/app/public.js
  24. 7
      route/static/app/soft.js
  25. 2
      route/templates/default/index.html

@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.16.2'
__version = '0.16.2.2'
__api_addr = 'data/api.json'
def __init__(self):

@ -299,7 +299,8 @@ class system_api:
data_list = data.strip().split("\n")
mac_version = ''
for x in data_list:
mac_version += x.split("\t")[1] + ' '
xlist = x.split("\t")
mac_version += xlist[len(xlist)-1] + ' '
arch_ver = mw.execShell("arch")
return mac_version + " (" + arch_ver[0].strip() + ")"
@ -366,15 +367,15 @@ class system_api:
mem = psutil.virtual_memory()
if mw.getOs() == 'darwin':
memInfo = {
'memTotal': mem.total / 1024 / 1024
'memTotal': mem.total,
}
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
else:
memInfo = {
'memTotal': mem.total / 1024 / 1024,
'memFree': mem.free / 1024 / 1024,
'memBuffers': mem.buffers / 1024 / 1024,
'memCached': mem.cached / 1024 / 1024
'memTotal': mem.total,
'memFree': mem.free,
'memBuffers': mem.buffers,
'memCached': mem.cached
}
memInfo['memRealUsed'] = memInfo['memTotal'] - \
@ -558,9 +559,9 @@ class system_api:
networkInfo['upTotal'] = networkIo[0]
networkInfo['downTotal'] = networkIo[1]
networkInfo['up'] = round(float(
networkIo[0] - session['up']) / 1024 / (ntime - session['otime']), 2)
networkIo[0] - session['up']) / (ntime - session['otime']), 2)
networkInfo['down'] = round(
float(networkIo[1] - session['down']) / 1024 / (ntime - session['otime']), 2)
float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
networkInfo['downPackets'] = networkIo[3]
networkInfo['upPackets'] = networkIo[2]

@ -12,6 +12,7 @@
<p onclick="myPerfOpt();">性能优化</p>
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mariadb',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="myBinLogs();">BINLOG</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>

@ -90,6 +90,12 @@ def getDataDir():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getPidFile():
file = getConf()
@ -294,6 +300,53 @@ def binLog():
mw.writeFile(conf, con)
return mw.returnJson(True, '设置成功!')
def binLogList():
args = getArgs()
data = checkArgs(args, ['page', 'page_size', 'tojs'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
abspath = data_dir + '/' + f
t['name'] = f
t['size'] = os.path.getsize(abspath)
t['time'] = mw.getDataFromInt(os.path.getctime(abspath))
log_bin_l.append(t)
log_bin_l = sorted(log_bin_l, key=lambda x: x['time'], reverse=True)
# print(log_bin_l)
# print(data_dir, log_bin_name)
count = len(log_bin_l)
page_start = (page - 1) * page_size
page_end = page_start + page_size
if page_end > count:
page_end = count
data = {}
page_args = {}
page_args['count'] = count
page_args['p'] = page
page_args['row'] = page_size
page_args['tojs'] = args['tojs']
data['page'] = mw.getPage(page_args)
data['data'] = log_bin_l[page_start:page_end]
return mw.getJson(data)
def cleanBinLog():
db = pMysqlDb()
@ -302,21 +355,6 @@ def cleanBinLog():
return mw.returnJson(True, '清理BINLOG成功!')
def setSkipGrantTables(v):
'''
设置是否密码验证
'''
conf = getConf()
con = mw.readFile(conf)
if v:
if con.find('#skip-grant-tables') != -1:
con = con.replace('#skip-grant-tables', 'skip-grant-tables')
else:
con = con.replace('skip-grant-tables', '#skip-grant-tables')
mw.writeFile(conf, con)
return True
def getErrorLog():
args = getArgs()
path = getDataDir()
@ -579,7 +617,7 @@ def setMyPort():
restart()
return mw.returnJson(True, '编辑成功!')
# python3 plugins/mariadb/index.py run_info {}
def runInfo(version):
if status(version) == 'stop':
@ -760,6 +798,8 @@ def rootPwd():
'id=?', (1,)).getField('mysql_root')
# python3 plugins/mariadb/index.py import_db_external {"file":"xx.sql","name":"demo1"}
# python3 plugins/mariadb/index.py import_db_external {"file":"db_demo1_20231221_203614 2.sql","name":"demo1"}
def importDbExternal():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
@ -806,6 +846,9 @@ def importDbExternal():
mw.execShell(cmd)
import_sql = import_dir + tmpFile
if file.find(".sql") > -1 and file.find(".sql.gz") == -1:
import_sql = import_dir + file
if import_sql == "":
return mw.returnJson(False, '未找SQL文件')
@ -813,12 +856,14 @@ def importDbExternal():
sock = getSocketFile()
os.environ["MYSQL_PWD"] = pwd
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p"' + \
pwd + '" ' + name + ' < "' + import_sql+'"'
# print(mysql_cmd)
os.system(mysql_cmd)
os.remove(import_sql)
if ext != 'sql':
os.remove(import_sql)
return mw.returnJson(True, 'ok')
@ -982,7 +1027,7 @@ def syncGetDatabases():
host = user["Host"]
break
ps = mw.getMsg('INPUT_PS')
ps = vdb_name
if vdb_name == 'test':
ps = mw.getMsg('DATABASE_TEST')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
@ -1054,12 +1099,21 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb('mysql')
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
cmd = "ALTER USER 'root'@'localhost' IDENTIFIED BY '" + password + "';"
@ -1069,7 +1123,12 @@ def setRootPwd(version=''):
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
orm = pMysqlDb()
orm.execute("flush privileges")
return mw.returnJson(True, '数据库root密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!' + msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
@ -1276,16 +1335,58 @@ def setDbAccess():
psdb.where('username=?', (name,)).save('accept,rw', (access, 'rw',))
return mw.returnJson(True, '设置成功!')
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
db_option = "-S " + serverdir + "/mysql.sock"
cmd_pass = serverdir + '/bin/mariadb ' + db_option + ' -uroot -e'
cmd_pass = cmd_pass + \
"\"flush privileges;use mysql;grant all privileges on *.* to 'root'@'localhost' identified by '" + pwd + "';"
cmd_pass = cmd_pass + "flush privileges;\""
data = mw.execShell(cmd_pass)
# print(data)
return True
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
pdb = pMysqlDb()
psdb = pSqliteDb('databases')
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
mw.execShell("rm -rf " + getServerDir() + "/data")
openSkipGrantTables()
appCMD(version, 'start')
time.sleep(3)
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
@ -1588,6 +1689,13 @@ def setDbMasterAccess():
psdb.where('username=?', (username,)).save('accept', (access,))
return mw.returnJson(True, '设置成功!')
def resetMaster(version=''):
pdb = pMysqlDb()
r = pdb.execute('reset master')
isError = isSqlError(r)
if isError != None:
return isError
return mw.returnJson(True, '重置成功!')
def getMasterDbList(version=''):
args = getArgs()
@ -1899,8 +2007,7 @@ def getMasterRepSlaveUserCmd(version):
if mode == "gtid":
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + "', " + "MASTER_LOG_FILE='" + mstatus[0]["File"] + \
"',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
clist[0]['password'] + "',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
else:
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
@ -2186,6 +2293,58 @@ def getSlaveList(version=''):
data['data'] = dlist
return mw.getJson(data)
def trySlaveSyncBugfix(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode != 'sync-user':
return mw.returnJson(False, '仅支持【同步账户】模式')
conn = pSqliteDb('slave_sync_user')
slave_sync_data = conn.field('ip,port,user,pass,mode,cmd').select()
if len(slave_sync_data) < 1:
return mw.returnJson(False, '需要先添加【同步用户】配置!')
# print(slave_sync_data)
# 本地从库
sdb = pMysqlDb()
gtid_purged = ''
for i in range(len(slave_sync_data)):
port = slave_sync_data[i]['port']
password = slave_sync_data[i]['pass']
host = slave_sync_data[i]['ip']
user = slave_sync_data[i]['user']
# print(port, password, host)
mdb = mw.getMyORM()
mdb.setHost(host)
mdb.setPort(port)
mdb.setUser(user)
mdb.setPwd(password)
mdb.setSocket('')
# var_gtid = mdb.query('show VARIABLES like "%gtid_purged%"')
var_gtid = mdb.query('select @@global.gtid_current_pos as Value')
#print(var_gtid)
if len(var_gtid) > 0:
gtid_purged += var_gtid[0]['Value'] + ','
gtid_purged = gtid_purged.strip(',')
sql = "set @@global.gtid_slave_pos='" + gtid_purged + "'"
sdb.query('stop all slaves')
# print(sql)
sdb.query(sql)
sdb.query('start all slaves')
return mw.returnJson(True, '修复成功!')
def getSlaveSyncCmd(version=''):
root = mw.getRunDir()
@ -2226,7 +2385,7 @@ def parseSlaveSyncCmd(cmd):
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
return a
# python3 plugins/mariadb/index.py init_slave_status {}
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
@ -2267,7 +2426,7 @@ def initSlaveStatusSyncUser(version=''):
try:
pinfo = parseSlaveSyncCmd(cmd_sql)
except Exception as e:
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
return mw.returnJson(False, base_t + '->CMD同步命令不合规范:'+str(e))
pdb.query(cmd_sql)
@ -2452,8 +2611,7 @@ def fullSync(version=''):
if args['begin'] == '1':
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
getPluginDir() + \
'/index.py do_full_sync {"db":"' + \
args['db'] + '","sign":"' + sign + '"} &'
'/index.py do_full_sync {"db":"' + args['db'] + '","sign":"' + sign + '"} &'
# print(cmd)
mw.execShell(cmd)
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
@ -2475,6 +2633,7 @@ def fullSync(version=''):
return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
# python3 plugins/mariadb/index.py do_full_sync {"db":"demo1","sign":"","beigin":"1"}
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
@ -2512,13 +2671,16 @@ def doFullSyncUser(version=''):
ip = data['ip']
bak_file = '/tmp/tmp.sql'
if os.path.exists(bak_file):
os.system("rm -rf " + bak_file)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 10})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
# https://mariadb.com/kb/zh-cn/mariadb-dump/
dump_sql_data = getServerDir() + "/bin/mariadb-dump -f --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p'" + apass + "' " + sync_db + ">" + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
@ -2526,8 +2688,9 @@ def doFullSyncUser(version=''):
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db + '<' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
pinfo = parseSlaveSyncCmd(data['cmd'])
@ -2729,6 +2892,8 @@ if __name__ == "__main__":
print(getConf())
elif func == 'bin_log':
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':
@ -2797,6 +2962,8 @@ if __name__ == "__main__":
print(getDbrunMode(version))
elif func == 'set_dbrun_mode':
print(setDbrunMode(version))
elif func == 'reset_master':
print(resetMaster(version))
elif func == 'get_masterdb_list':
print(getMasterDbList(version))
elif func == 'get_master_status':
@ -2821,6 +2988,8 @@ if __name__ == "__main__":
print(getMasterRepSlaveUserCmd(version))
elif func == 'get_slave_list':
print(getSlaveList(version))
elif func == 'try_slave_sync_bugfix':
print(trySlaveSyncBugfix(version))
elif func == 'get_slave_sync_cmd':
print(getSlaveSyncCmd(version))
elif func == 'get_slave_ssh_list':

@ -0,0 +1,186 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import re
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
if mw.isAppleSystem():
cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
info = mw.execShell(cmd)
p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
sys.path.append(p)
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'mariadb'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getSPluginDir():
return '/www/server/mdserver-web/plugins/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConf():
path = getServerDir() + '/etc/my.cnf'
return path
def getDataDir():
file = getConf()
content = mw.readFile(file)
rep = 'datadir\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getRelayLogName():
file = getConf()
content = mw.readFile(file)
rep = 'relay-log\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def binLogListLook(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListLookDecode(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceRelay(args):
rdata = {}
file = args['file']
line = args['line']
relay_name = getRelayLogName()
data_dir = getDataDir()
alist = os.listdir(data_dir)
relay_list = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(relay_name) and not f.endswith('.index'):
relay_list.append(f)
relay_list = sorted(relay_list, reverse=True)
if len(relay_list) == 0:
rdata['cmd'] = ''
rdata['data'] = '无Relay日志'
return rdata
file = relay_list[0]
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceBinLog(args):
rdata = {}
file = args['file']
line = args['line']
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
log_bin_l.append(f)
if len(log_bin_l) == 0:
rdata['cmd'] = ''
rdata['data'] = '无BINLOG'
return rdata
log_bin_l = sorted(log_bin_l, reverse=True)
file = log_bin_l[0]
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata

@ -58,6 +58,62 @@ function myAsyncPost(method,args){
return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
}
function myPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'mariadb';
req_data['func'] = method;
req_data['script']='index_mariadb';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function myPostCallbakN(method, version, args,callback){
var req_data = {};
req_data['name'] = 'mariadb';
req_data['func'] = method;
req_data['script']='index_mariadb';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function runInfo(){
myPost('run_info','',function(data){
@ -83,7 +139,7 @@ function runInfo(){
<tr><th>活动/峰值连接数</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">,max_connections</td></tr>\
<tr><th>线程缓存命中率</th><td>' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '%</td><td colspan="2">,thread_cache_size</td></tr>\
<tr><th>索引命中率</th><td>' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">,key_buffer_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">,innodb_buffer_pool_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + (rdata.Innodb_buffer_pool_read_requests / (rdata.Innodb_buffer_pool_read_requests+rdata.Innodb_buffer_pool_reads)).toFixed(2) + '%</td><td colspan="2">,innodb_buffer_pool_size</td></tr>\
<tr><th>查询缓存命中率</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>创建临时表到磁盘</th><td>' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '%</td><td colspan="2">,tmp_table_size</td></tr>\
<tr><th>已打开的表</th><td>' + rdata.Open_tables + '</td><td colspan="2">,table_cache_size</td></tr>\
@ -438,13 +494,24 @@ function syncToDatabase(type){
}
function setRootPwd(type, pwd){
if (type==1){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
dbList();
},{icon: rdata.status ? 1 : 2});
});
return;
}
var index = layer.open({
type: 1,
area: '500px',
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交","关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@ -454,16 +521,36 @@ function setRootPwd(type, pwd){
</div>\
</div>\
</form>",
yes:function(index,layero){
yes:function(layerIndex){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
layer.close(index);
},{icon: rdata.status ? 1 : 2});
});
return;
},
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@ -1160,6 +1247,146 @@ function dbList(page, search){
});
}
function myBinRollingLogs(_name, func, _args, line){
var file_line = 100;
if ( typeof(line) != 'undefined' ){
file_line = line;
}
var reqTimer = null;
function requestLogs(func,file,line){
myPostCallbakN(func,'',{'file':file,"line":line}, function(rdata){
var data = rdata.data.data;
var cmd = rdata.data.cmd;
if(data == '') {
data = '当前没有日志!';
}
$('#my_rolling_cmd').html(cmd);
$('#my_rolling_copy').click(function(){
copyText(cmd);
});
var ebody = '<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log">'+data+'</textarea>';
$("#my_rolling_logs").html(ebody);
var ob = document.getElementById('roll_info_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: _name + '日志',
area: ['800px','700px'],
end: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
content:'<div class="change-default" style="padding:0px 20px 0px;">\
<div class="divtable mtb10">\
<table class="table table-hover"><tr>\
<td id="my_rolling_cmd">cmd</td>\
<td id="my_rolling_copy" style="width:35px;"><span class="ico-copy cursor btcopy" title="复制密码"></span></td>\
<tr>\
</table>\
</div>\
</div>\
<div class="change-default" style="padding:0px 20px 0px;" id="my_rolling_logs">\
<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log"></textarea>\
</div>',
success:function(){
var fileName = _args['file'];
requestLogs(func,fileName,file_line);
reqTimer = setInterval(function(){
requestLogs(func,fileName,file_line);
},1000);
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
_data['tojs'] = 'myBinLogsRender';
myPost('binlog_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var list = '';
for(i in rdata.data){
list += '<tr>';
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td>' + toSize(rdata.data[i]['size'])+'</td>';
list += '<td>' + rdata.data[i]['time'] +'</td>';
list += '<td style="text-align:right">';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look" class="btlink">查看</a> | ';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look_decode" class="btlink">解码查看</a>';
list += '</td></tr>';
}
if (rdata.data.length ==0){
list = '<tr><td colspan="4">无数据</td</tr>';
}
$("#binlog_list tbody").html(list);
$('#binlog_page').html(rdata.page);
$('#binlog_list .look').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看BINLOG','binLogListLook',{'file':file },100);
});
$('#binlog_list .look_decode').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看解码BINLOG','binLogListLookDecode',{'file':file },100);
});
});
}
function myBinLogs(){
var con = '<div class="safe bgw">\
<button class="btn btn-success btn-sm relay_trace" type="button" style="margin-right: 5px;">中继日志跟踪</button>\
<button class="btn btn-default btn-sm binlog_trace" type="button" style="margin-right: 5px;">最新BINLOG日志跟踪</button>\
<div id="binlog_list" class="divtable mtb10">\
<div class="tablescroll">\
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>文件名称</th>\
<th>大小</th>\
<th>时间</th>\
<th style="text-align:right;">操作</th>\
</tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="binlog_page" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
myBinLogsRender(1);
$('.soft-man-con .relay_trace').click(function(){
myBinRollingLogs('中继日志跟踪','binLogListTraceRelay',{'file':''},100);
});
$('.soft-man-con .binlog_trace').click(function(){
myBinRollingLogs('最新BINLOG日志跟踪','binLogListTraceBinLog',{'file':''},100);
});
}
function myLogs(){
@ -1603,6 +1830,14 @@ function setDbMasterAccess(username){
});
}
function resetMaster(){
myPost('reset_master', '', function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
},{icon: rdata.status ? 1 : 2});
},'正在执行重置master命令[reset master]');
}
function getMasterRepSlaveList(){
var _data = {};
if (typeof(page) =='undefined'){
@ -2329,11 +2564,16 @@ function masterOrSlaveConf(version=''){
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
</tr>";
var btn_list = ['复制错误',"取消"];
if (info['Last_IO_Error'].search(/1236/i)>0){
btn_list = ['复制错误',"取消","尝试修复"];
}
layer.open({
type: 1,
title: '同步异常信息',
area: ['600px','300px'],
btn:['复制错误',"取消"],
btn:btn_list,
content:"<form class='bt-form pd15'>\
<div class='divtable mtb10'>\
<div class='tablescroll'>\
@ -2348,10 +2588,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@ -2368,6 +2618,14 @@ function masterOrSlaveConf(version=''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
btn3:function(){
myPost('try_slave_sync_bugfix', {}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){
masterOrSlaveConf();
},{ icon: rdata.status ? 1 : 5 },2000);
});
}
});
});
@ -2437,6 +2695,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Master[]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.status ? 'btn-danger' : 'btn-success')+' btn-xs btn-master">'+(!rdata.status ? '未开启' : '已开启') +'</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()">重置</button>\
</p>\
<hr/>\
<!-- master list -->\

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.11.2
MY_VER=10.11.6
Install_app()
{

@ -13,7 +13,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.6.12
MY_VER=10.6.16
Install_app()
{

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.9.5
MY_VER=10.9.8
Install_app()
{

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.0.3
MY_VER=11.0.4
Install_app()
{

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.1.2
MY_VER=11.1.3
Install_app()
{

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.2.1
MY_VER=11.2.2
Install_app()
{

@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.3.0
MY_VER=11.3.1
Install_app()
{

@ -0,0 +1,108 @@
[client]
user = root
#password = your_password
port = 33206
socket = {$SERVER_APP_PATH}/mysql.sock
default-character-set = UTF8MB4
[mysqld]
!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
authentication_policy=mysql_native_password
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 33206
mysqlx_port = 33260
socket = {$SERVER_APP_PATH}/mysql.sock
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
server-id = {$SERVER_ID}
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
default_storage_engine = InnoDB
key_buffer_size = 8M
table_open_cache = 32
sort_buffer_size = 256K
net_buffer_length = 4K
read_buffer_size = 128K
read_rnd_buffer_size = 256K
myisam_sort_buffer_size = 4M
thread_cache_size = 4
lower_case_table_names=1
tmp_table_size = 8M
character-set-server = UTF8MB4
max_connections = 500
max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
#skip-external-locking
#skip-grant-tables
#loose-skip-innodb
#skip-networking
#skip-name-resolve
log-bin=mysql-bin
binlog_format=mixed
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
long_query_time=3
#log_queries_not_using_indexes=on
relay-log=mdserver
relay-log-index=mdserver
#master
#sync_binlog=1
#binlog-do-db
binlog-ignore-db = test
binlog-ignore-db = mysql
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#slave
log_replica_updates
#replicate-do-db
slave_skip_errors=1062,1396
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
master_info_repository = table
relay_log_info_repository = table
default_storage_engine = InnoDB
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
innodb_buffer_pool_size = 16M
innodb_redo_log_capacity=10485760
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
innodb_write_io_threads = 1
innodb_file_per_table=1
binlog_expire_logs_seconds=2592000
secure-file-priv={$SERVER_APP_PATH}/tmp
[mysqldump]
quick
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M
[mysqlhotcopy]
interactive-timeout

@ -6,7 +6,7 @@
"type":"运行环境",
"ps":"一种关系数据库管理系统[debian,ubuntu](极速安装)",
"todo_versions":["5.7","8.0"],
"versions":["5.7","8.0"],
"versions":["5.7","8.0","8.2"],
"shell":"install.sh",
"install_pre_inspection":true,
"checks":"server/mysql-apt",

@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export DEBIAN_FRONTEND=noninteractive
# https://downloads.mysql.com/archives/community/
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
myDir=${serverPath}/source/mysql-apt
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh install 8.0
# 暂时debian12没有标准版,先用11使用
if [ "$OSNAME" == 'debian' ] && [ "$VERSION_ID" == '12' ] ;then
echo "暂时不支持该${OSNAME}${VERSION_ID}" > $install_tmp
exit 1
fi
ARCH="amd64"
TMP_ARCH=`arch`
if [ "$TMP_ARCH" == "x86_64" ];then
ARCH="amd64"
elif [ "$TMP_ARCH" == "aarch64" ];then
ARCH="arm64"
else
ARCH="amd64"
fi
if [ "$ARCH" != "amd64" ];then
echo "暂时不支持该${ARCH}" > $install_tmp
exit 1
fi
MYSQL_VER=8.2.0
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_${ARCH}
# /lib/systemd/system/mysql.service
# /etc/mysql/my.cnf
APT_INSTALL()
{
########
mkdir -p $myDir
mkdir -p $serverPath/mysql-apt/bin
wget --no-check-certificate -O ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar https://cdn.mysql.com/archives/mysql-8.2/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
chmod +x ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
cd ${myDir} && tar vxf ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
apt update -y
apt install -y libnuma1 libaio1 libmecab2
# 安装
dpkg -X mysql-common_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client-plugins_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client-core_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-client_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-server-core_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-server_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-server_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
# 测试时可关闭
rm -rf $myDir
#######
}
APT_UNINSTALL()
{
###
rm -rf $myDir
# apt remove -y mysql-server
###
}
Install_mysql()
{
echo '正在安装脚本文件...' > $install_tmp
if id mysql &> /dev/null ;then
echo "mysql uid is `id -u mysql`"
echo "mysql shell is `grep "^mysql:" /etc/passwd |cut -d':' -f7 `"
else
groupadd mysql
useradd -g mysql mysql
fi
isApt=`which apt`
if [ "$isApt" != "" ];then
APT_INSTALL
fi
if [ "$?" == "0" ];then
mkdir -p $serverPath/mysql-apt
echo '8.0' > $serverPath/mysql-apt/version.pl
echo '安装完成' > $install_tmp
else
echo '8.0' > $serverPath/mysql-apt/version.pl
echo "暂时不支持该系统" > $install_tmp
fi
}
Uninstall_mysql()
{
isApt=`which apt`
if [ "$isApt" != "" ];then
APT_UNINSTALL
fi
rm -rf $serverPath/mysql-apt
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_mysql
else
Uninstall_mysql
fi

@ -192,7 +192,11 @@ def pMysqlDb():
def makeInitRsaKey(version=''):
datadir = getServerDir() + "/data"
try:
datadir = getDataDir()
except Exception as e:
datadir = getServerDir() + "/data"
mysql_pem = datadir + "/mysql.pem"
if not os.path.exists(mysql_pem):
rdata = mw.execShell(
@ -405,22 +409,6 @@ def cleanBinLog():
db.execute("PURGE MASTER LOGS BEFORE '" + cleanTime + "';")
return mw.returnJson(True, '清理BINLOG成功!')
def setSkipGrantTables(v):
'''
设置是否密码验证
'''
conf = getConf()
con = mw.readFile(conf)
if v:
if con.find('#skip-grant-tables') != -1:
con = con.replace('#skip-grant-tables', 'skip-grant-tables')
else:
con = con.replace('skip-grant-tables', '#skip-grant-tables')
mw.writeFile(conf, con)
return True
def getErrorLog():
args = getArgs()
filename = getErrorLogsFile()
@ -536,7 +524,6 @@ def initMysqlPwd():
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
return True
def initMysql8Pwd():
time.sleep(8)
@ -1067,7 +1054,7 @@ def importDbExternal():
myPass(True, pwd)
mysql_cmd = getServerDir() + '/bin/mysql --defaults-file=' + my_cnf + \
' -uroot -p\"' + pwd + '\" -f ' + name + ' < ' + import_sql
' -uroot -p"' + pwd + '" -f ' + name + ' < ' + import_sql
# print(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
@ -1105,8 +1092,8 @@ def importDbBackup():
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + name + ' < ' + file_path_sql
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p"' + pwd + \
'" ' + name + ' < ' + file_path_sql
# print(mysql_cmd)
# os.system(mysql_cmd)
@ -1274,7 +1261,7 @@ def syncGetDatabases():
host = user["Host"]
break
ps = mw.getMsg('INPUT_PS')
ps = vdb_name
if vdb_name == 'test':
ps = mw.getMsg('DATABASE_TEST')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
@ -1346,12 +1333,20 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb()
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
if version.find('5.7') > -1 or version.find('8.0') > -1:
@ -1366,7 +1361,12 @@ def setRootPwd(version=''):
"update mysql.user set Password=password('" + password + "') where User='root'")
pdb.execute("flush privileges")
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '数据库root密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!'+msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
@ -1576,15 +1576,79 @@ def setDbAccess():
return mw.returnJson(True, '设置成功!')
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
if float(version) < 5.7:
cmd_pass = serverdir + '/bin/mysql --defaults-file=' + myconf + ' -uroot -e'
cmd_pass = cmd_pass + '"UPDATE mysql.user SET password=PASSWORD(\'' + pwd + "') WHERE user='root';"
cmd_pass = cmd_pass + 'flush privileges;"'
data = mw.execShell(cmd_pass)
# print(data)
else:
auth_policy = getAuthPolicy()
reset_pwd = 'flush privileges;'
reset_pwd = reset_pwd + \
"UPDATE mysql.user SET authentication_string='' WHERE user='root';"
reset_pwd = reset_pwd + "flush privileges;"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED by '" + pwd + "';"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
reset_pwd = reset_pwd + "flush privileges;"
tmp_file = "/tmp/mysql_init_tmp.log"
mw.writeFile(tmp_file, reset_pwd)
cmd_pass = serverdir + '/bin/mysql --defaults-file=' + myconf + ' -uroot -proot < ' + tmp_file
data = mw.execShell(cmd_pass)
# print(data)
os.remove(tmp_file)
return True
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
pdb = pMysqlDb()
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
mw.execShell("rm -rf " + getServerDir() + "/data")
openSkipGrantTables()
appCMD(version, 'start')
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
except Exception as e:
@ -2882,6 +2946,8 @@ def doFullSyncUser(version=''):
ip = data['ip']
bak_file = '/tmp/tmp.sql'
if os.path.exists(bak_file):
os.system("rm -rf " + bak_file)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
@ -2893,18 +2959,18 @@ def doFullSyncUser(version=''):
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p\"" + apass + \
"\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
# print(dump_sql_data)
port + " -u" + user + " -p'" + apass + \
"' --ssl-mode=DISABLED " + sync_db + " > " + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db_import + ' < ' + bak_file
# print(my_import_cmd)
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db_import + ' < ' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
if version == '8.0':
@ -3150,8 +3216,6 @@ if __name__ == "__main__":
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'binlog_look':
print(binLogListLook())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':

@ -161,7 +161,7 @@ function runInfo(){
<tr><th>活动/峰值连接数</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">,max_connections</td></tr>\
<tr><th>线程缓存命中率</th><td>' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '%</td><td colspan="2">,thread_cache_size</td></tr>\
<tr><th>索引命中率</th><td>' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">,key_buffer_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">,innodb_buffer_pool_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + (rdata.Innodb_buffer_pool_read_requests / (rdata.Innodb_buffer_pool_read_requests+rdata.Innodb_buffer_pool_reads)).toFixed(2) + '%</td><td colspan="2">,innodb_buffer_pool_size</td></tr>\
<tr><th>查询缓存命中率</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>创建临时表到磁盘</th><td>' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '%</td><td colspan="2">,tmp_table_size</td></tr>\
<tr><th>已打开的表</th><td>' + rdata.Open_tables + '</td><td colspan="2">,table_cache_size</td></tr>\
@ -507,7 +507,7 @@ function setRootPwd(type, pwd){
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交", "复制ROOT密码", "关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@ -523,13 +523,30 @@ function setRootPwd(type, pwd){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
},
btn2:function(){
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@ -684,7 +701,7 @@ function setDbPass(id, username, password){
<span title='随机密码' class='glyphicon glyphicon-repeat cursor' onclick='repeatPwd(16)'></span></div>\
</div>\
<input type='hidden' name='id' value='"+id+"'>\
</form>",
</form>",
yes:function(index){
// var data = $("#mod_pwd").serialize();
var data = {};
@ -1291,6 +1308,7 @@ function myBinRollingLogs(_name, func, _args, line){
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
@ -2577,10 +2595,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@ -2675,7 +2703,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Master[]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.status ? 'btn-danger' : 'btn-success')+' btn-xs btn-master">'+(!rdata.status ? '未开启' : '已开启') +'</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()" >重置</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()">重置</button>\
</p>\
<hr/>\
<!-- master list -->\

@ -5,7 +5,7 @@
"name": "php-apt",
"title": "PHP[APT]",
"coexist": true,
"versions": ["56","70","71","72","73","74","80","81","82"],
"versions": ["56","70","71","72","73","74","80","81","82","83"],
"install_pre_inspection":true,
"tip": "soft",
"checks": "server/php-apt/VERSION",

@ -0,0 +1,49 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sourcePath=${serverPath}/source
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
#获取信息和版本
# bash /www/server/mdsever-web/scripts/getos.sh
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
version=8.3
PHP_VER=83
Install_php()
{
#------------------------ install start ------------------------------------#
apt -y install php${version} php${version}-fpm php${version}-dev
if [ "$?" == "0" ];then
mkdir -p $serverPath/php-apt/${PHP_VER}
fi
#------------------------ install end ------------------------------------#
}
Uninstall_php()
{
#------------------------ uninstall start ------------------------------------#
apt -y remove php${version} php${version}-*
rm -rf $serverPath/php-apt/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
#------------------------ uninstall start ------------------------------------#
}
action=${1}
if [ "${1}" == 'install' ];then
Install_php
else
Uninstall_php
fi

@ -10,7 +10,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "数据库访问抽象模块!",
@ -28,7 +29,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@ -46,7 +48,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@ -64,7 +67,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用sqlite3数据库的模块!",
@ -90,7 +94,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用ODBC数据库的模块!",
@ -142,7 +147,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "用于加速PHP脚本!",
@ -175,7 +181,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "高精度计算!",
@ -239,7 +246,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用CURL库!",
@ -252,7 +260,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用GD库!",
@ -270,7 +279,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "提供国际化支持",
@ -300,7 +310,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "强大的内容缓存器,支持集群",
@ -317,7 +328,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "更强大的内容缓存器,支持集群",
@ -334,7 +347,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "脚本缓存器",
@ -352,7 +367,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "比GD更强大的图形库",
@ -369,7 +385,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "调试器",
"msg": "不多说,不了解的不要安装",
@ -386,7 +404,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "性能分析",
"msg": "不多说,不了解的不要安装!",
@ -403,7 +423,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "异步、并行、高性能网络通信引擎",
@ -463,7 +485,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "框架",
"msg": "Yar是一个RPC框架",
@ -541,7 +565,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "日志",
"msg": "SeasLog高性能日志记录",
@ -559,7 +585,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "用于需要多字节字符串处理的模块",
@ -577,7 +604,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
@ -594,7 +622,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",

@ -6,7 +6,7 @@ $(function() {
$(this).find(".mask").css({ "color": "#d2edd8" });
$(this).find(".mem-re-con").css({ "display": "block" });
$(this).find(".mem-re-con").animate({ "top": "0", opacity: 1 });
$("#memory").text(lan.index.memre);
$("#memory").text('内存释放');
}
}, function() {
$(this).removeClass("shine_green");
@ -29,6 +29,7 @@ $(function() {
}
});
});
//获取负载
function getLoad(data) {
$("#LoadList .mask").html("<span id='Load' style='font-size:14px'>获取中..</span>");
@ -83,19 +84,18 @@ function showCpuTips(rdata){
$('#cpuChart .mask').unbind();
$('#cpuChart .mask').hover(function() {
var cpuText = '';
if (rdata.cpu[2].length == 1){
var cpuUse = parseFloat(rdata.cpu[2][0] == 0 ? 0 : rdata.cpu[2][0]).toFixed(1);
cpuText += 'CPU-1:' + cpuUse + '%'
} else{
cpuText += 'CPU-1:' + cpuUse + '%';
} else {
for (var i = 1; i < rdata.cpu[2].length + 1; i++) {
var cpuUse = parseFloat(rdata.cpu[2][i - 1] == 0 ? 0 : rdata.cpu[2][i - 1]).toFixed(1);
if (i % 2 != 0) {
cpuText += 'CPU-' + i + ':' + cpuUse + '%&nbsp;|&nbsp;'
} else {
cpuText += 'CPU-' + i + ':' + cpuUse + '%'
cpuText += '\n'
}
var cpuUse = parseFloat(rdata.cpu[2][i - 1] == 0 ? 0 : rdata.cpu[2][i - 1]).toFixed(1);
if (i % 2 != 0) {
cpuText += 'CPU-' + i + ':' + cpuUse + '%&nbsp;|&nbsp;';
} else {
cpuText += 'CPU-' + i + ':' + cpuUse + '%';
cpuText += '\n';
}
}
}
layer.tips(rdata.cpu[3] + "</br>" + rdata.cpu[5] + "个物理CPU," + (rdata.cpu[4]) + "个物理核心," + rdata.cpu[1] + "个逻辑核心</br>" + cpuText, this, { time: 0, tips: [1, '#999'] });
@ -109,6 +109,7 @@ function rocket(sum, m) {
var n = sum - m;
$(".mem-release").find(".mask span").text(n);
}
//释放内存
function reMemory() {
setTimeout(function() {
@ -199,27 +200,34 @@ function clearSystem() {
}
function setMemImg(info){
setCookie("memRealUsed", parseInt(info.memRealUsed));
$("#memory").html(parseInt(info.memRealUsed) + '/' + parseInt(info.memTotal) + ' (MB)');
setCookie("mem-before", $("#memory").text());
if (!getCookie('memSize')) setCookie('memSize', parseInt(info.memTotal));
var memRealUsed = toSize(info.memRealUsed);
var memTotal = toSize(info.memTotal);
var memRealUsedVal = memRealUsed.split(' ')[0];
var memTotalVal = memTotal.split(' ')[0];
var unit = memTotal.split(' ')[1];
var mem_txt = memRealUsedVal + '/' + memTotalVal + ' ('+ unit +')';
setCookie("mem-before", mem_txt);
$("#memory").html(mem_txt);
var memPre = Math.floor(info.memRealUsed / (info.memTotal / 100));
$("#left").html(memPre);
setcolor(memPre, "#left", 75, 90, 95);
$("#state").html(info.cpuRealUsed);
setcolor(memPre, "#state", 30, 70, 90);
setImg();
var memFree = info.memTotal - info.memRealUsed;
if (memFree/(1024*1024) < 64) {
$("#messageError").show();
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;">当前可用物理内存小于64M,这可能导致MySQL自动停止,站点502等错误,请尝试释放内存!</span></p>')
}
}
function getInfo() {
$.get("/system/system_total", function(info) {
setCookie("memRealUsed", parseInt(info.memRealUsed));
$("#memory").html(parseInt(info.memRealUsed) + '/' + parseInt(info.memTotal) + ' (MB)');
setCookie("mem-before", $("#memory").text());
if (!getCookie('memSize')) setCookie('memSize', parseInt(info.memTotal));
var memPre = Math.floor(info.memRealUsed / (info.memTotal / 100));
$("#left").html(memPre);
setcolor(memPre, "#left", 75, 90, 95);
setMemImg(info);
$("#info").html(info.system);
$("#running").html(info.time);
var _system = info.system;
@ -240,13 +248,8 @@ function getInfo() {
}
$("#core").html(info.cpuNum + ' 核心');
$("#state").html(info.cpuRealUsed);
setcolor(memPre, "#state", 30, 70, 90);
var memFree = info.memTotal - info.memRealUsed;
if (memFree < 64) {
$("#messageError").show();
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;">' + lan.index.mem_warning + '</span> </p>')
}
setcolor(info.cpuRealUsed, "#state", 30, 70, 90);
// if (info.isuser > 0) {
// $("#messageError").show();
@ -280,9 +283,10 @@ function setcolor(pre, s, s1, s2, s3) {
function getNet() {
var up, down;
$.get("/system/network", function(net) {
$("#InterfaceSpeed").html(lan.index.interfacespeed + ": 1.0Gbps");
$("#upSpeed").html(net.up + ' KB');
$("#downSpeed").html(net.down + ' KB');
$("#upSpeed").html(toSize(net.up));
$("#downSpeed").html(toSize(net.down));
$("#downAll").html(toSize(net.downTotal));
$("#downAll").attr('title', lan.index.package + ':' + net.downPackets)
$("#upAll").html(toSize(net.upTotal));
@ -292,18 +296,23 @@ function getNet() {
setcolor(net.cpu[0], "#state", 30, 70, 90);
setCookie("upNet", net.up);
setCookie("downNet", net.down);
//负载
getLoad(net.load);
// setMemImg(net.mem);
setImg();
//内存
setMemImg(net.mem);
//绑定hover事件
setImg();
showCpuTips(net);
},'json');
}
//网络Io
function netImg() {
var myChartNetwork = echarts.init(document.getElementById('netImg'));
var echartsNetImg = echarts.init(document.getElementById('netImg'));
var xData = [];
var yData = [];
var zData = [];
@ -333,10 +342,27 @@ function netImg() {
return ts(h) + ':' + ts(mm) + ':' + ts(s);
}
var default_unit = 'KB/s';
function addData(shift) {
xData.push(getTime());
yData.push(getCookie("upNet"));
zData.push(getCookie("downNet"));
if (getCookie("upNet") > getCookie("downNet") ){
tmp = getCookie("upNet");
} else {
tmp = getCookie("downNet");
}
var tmpSize = toSize(tmp);
default_unit = tmpSize.split(' ')[1] + '/s';
var upNetTmp = toSize(getCookie("upNet"));
var downNetTmp = toSize(getCookie("downNet"));
var upNetTmpSize = upNetTmp.split(' ')[0];
var downNetTmp = downNetTmp.split(' ')[0]
yData.push(upNetTmpSize);
zData.push(downNetTmp);
if (shift) {
xData.shift();
yData.shift();
@ -379,20 +405,16 @@ function netImg() {
}
},
yAxis: {
name: lan.index.unit + 'KB/s',
name: '单位 '+ default_unit,
splitLine: {
lineStyle: {
color: "#eee"
}
lineStyle: { color: "#eee" }
},
axisLine: {
lineStyle: {
color: "#666"
}
lineStyle: { color: "#666" }
}
},
series: [{
name: lan.index.net_up,
name: '上行',
type: 'line',
data: yData,
smooth: true,
@ -420,8 +442,9 @@ function netImg() {
width: 1
}
}
}, {
name: lan.index.net_down,
},
{
name: '下行',
type: 'line',
data: zData,
smooth: true,
@ -432,21 +455,21 @@ function netImg() {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(30, 144, 255,0.5)'
color: 'rgba(30, 144, 255,0.5)',
}, {
offset: 1,
color: 'rgba(30, 144, 255,0.8)'
color: 'rgba(30, 144, 255,0.8)',
}], false)
}
},
itemStyle: {
normal: {
color: '#52a9ff'
color: '#52a9ff',
}
},
lineStyle: {
normal: {
width: 1
width: 1,
}
}
}]
@ -454,7 +477,12 @@ function netImg() {
setInterval(function() {
getNet();
addData(true);
myChartNetwork.setOption({
echartsNetImg.setOption({
yAxis: {
name: '单位 '+ default_unit,
splitLine: { lineStyle: { color: "#eee" } },
axisLine: { lineStyle: { color: "#666" } }
},
xAxis: {
data: xData
},
@ -467,10 +495,11 @@ function netImg() {
}]
});
}, 3000);
// 使用刚指定的配置项和数据显示图表。
myChartNetwork.setOption(option);
echartsNetImg.setOption(option);
window.addEventListener("resize", function() {
myChartNetwork.resize();
echartsNetImg.resize();
});
}
@ -612,7 +641,6 @@ function reBoot() {
content: '<div class="rebt-con"><div class="rebt-li"><a data-id="server" href="javascript:;">重启服务器</a></div><div class="rebt-li"><a data-id="panel" href="javascript:;">重启面板</a></div></div>'
});
$('.rebt-con a').click(function () {
var type = $(this).attr('data-id');
switch (type) {
@ -737,6 +765,7 @@ function setSafeHide() {
setCookie('safeMsg', '1');
$("#safeMsg").remove();
}
//查看报告
function showDanger(num, port) {
var atxt = "因未使用安全隔离登录,所有IP都可以尝试连接,存在较高风险,请立即处理。";
@ -750,15 +779,15 @@ function showDanger(num, port) {
closeBtn: 1,
shift: 5,
content: '<div class="pd20">\
<table class="f14 showDanger"><tbody>\
<tr><td class="text-right" width="150">风险类型</td><td class="f16" style="color:red">暴力破解 <a href="https://www.bt.cn/bbs/thread-9562-1-1.html" class="btlink f14" style="margin-left:10px" target="_blank">说明</a></td></tr>\
<tr><td class="text-right">累计遭遇攻击总数</td><td class="f16" style="color:red">' + num + ' <a href="javascript:showDangerIP();" class="btlink f14" style="margin-left:10px"></a><span class="c9 f12" style="margin-left:10px"></span></td></tr>\
<tr><td class="text-right">风险等级</td><td class="f16" style="color:red"></td></tr>\
<tr><td class="text-right" style="vertical-align:top">风险描述</td><td style="line-height:20px">' + atxt + '</td></tr>\
<tr><td class="text-right" style="vertical-align:top">可参考解决方案</td><td><p style="margin-bottom:8px">SSHSSH</p><p>便</p></td></tr>\
</tbody></table>\
<div class="mtb20 text-center"><a href="https://www.bt.cn/admin/index.html" target="_blank" class="btn btn-success">立即部署隔离防护</a></div>\
</div>'
<table class="f14 showDanger"><tbody>\
<tr><td class="text-right" width="150">风险类型</td><td class="f16" style="color:red">暴力破解 <a href="https://www.bt.cn/bbs/thread-9562-1-1.html" class="btlink f14" style="margin-left:10px" target="_blank">说明</a></td></tr>\
<tr><td class="text-right">累计遭遇攻击总数</td><td class="f16" style="color:red">' + num + ' <a href="javascript:showDangerIP();" class="btlink f14" style="margin-left:10px"></a><span class="c9 f12" style="margin-left:10px"></span></td></tr>\
<tr><td class="text-right">风险等级</td><td class="f16" style="color:red"></td></tr>\
<tr><td class="text-right" style="vertical-align:top">风险描述</td><td style="line-height:20px">' + atxt + '</td></tr>\
<tr><td class="text-right" style="vertical-align:top">可参考解决方案</td><td><p style="margin-bottom:8px">SSHSSH</p><p>便</p></td></tr>\
</tbody></table>\
<div class="mtb20 text-center"><a href="https://www.bt.cn/admin/index.html" target="_blank" class="btn btn-success">立即部署隔离防护</a></div>\
</div>'
});
$(".showDanger td").css("padding", "8px")
}

@ -12,7 +12,7 @@ function toSize(a) {
if(a < e) {
return(b == 0 ? a : a.toFixed(2)) + d[b]
}
a /= e
a /= e;
}
}

@ -403,7 +403,12 @@ function indexListHtml(callback){
//首页软件列表
function indexSoft() {
indexListHtml(function(){
$("#indexsoft").dragsort({ dragSelector: ".spanmove", dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<div class='col-sm-3 col-md-3 col-lg-3 dashed-border'></div>" });
$("#indexsoft").dragsort({
dragSelector: ".spanmove",
dragBetween: true,
dragEnd: saveOrder,
placeHolderTemplate: "<div class='col-sm-3 col-md-3 col-lg-3 dashed-border'></div>"
});
});
function saveOrder() {

@ -135,7 +135,7 @@ setTimeout(function() {
setTimeout(function() {
getInfo();
}, 1500);
}, 200);
</script>
{% endblock %}
Loading…
Cancel
Save