mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 04:19:26 +08:00
Compare commits
67
Commits
midoks-patch-1
...
0.15.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c17314b634 | ||
|
|
92a4b28fbf | ||
|
|
733e4e81be | ||
|
|
8b99ae2515 | ||
|
|
2a72422402 | ||
|
|
145a259ef9 | ||
|
|
a34b7719c8 | ||
|
|
4d98455c35 | ||
|
|
c0c9def1fb | ||
|
|
02d8416466 | ||
|
|
d505740269 | ||
|
|
b1f6314df7 | ||
|
|
533653fe47 | ||
|
|
dff4551fb1 | ||
|
|
79723149a5 | ||
|
|
76da8a2ad5 | ||
|
|
645538e633 | ||
|
|
1a1b4e9f3a | ||
|
|
3afde01f93 | ||
|
|
a14db23971 | ||
|
|
316f06911b | ||
|
|
698d049314 | ||
|
|
d397d74f73 | ||
|
|
8a7447a4ee | ||
|
|
98414db41d | ||
|
|
7024185b59 | ||
|
|
495f16f2cf | ||
|
|
62444b7b6d | ||
|
|
50b11457f7 | ||
|
|
393cbc3974 | ||
|
|
ce3bfc2ebd | ||
|
|
b68e8f3650 | ||
|
|
08c83edeb9 | ||
|
|
c114e9aca8 | ||
|
|
c5123268d0 | ||
|
|
54bbc3ff57 | ||
|
|
4658b991a9 | ||
|
|
52145e710b | ||
|
|
4acc48ded2 | ||
|
|
0d858f87ea | ||
|
|
f37f08a9f5 | ||
|
|
0b5fc1de55 | ||
|
|
8748777101 | ||
|
|
48ed0b8034 | ||
|
|
41c9f6b7b6 | ||
|
|
c47336b65f | ||
|
|
24d7204ccc | ||
|
|
8c00fb8859 | ||
|
|
c573b28f16 | ||
|
|
afad548cf9 | ||
|
|
2605849de2 | ||
|
|
77598fa8a7 | ||
|
|
b175ab735d | ||
|
|
54ed17ab8f | ||
|
|
cadf72ea69 | ||
|
|
dadb737f88 | ||
|
|
fef2acf683 | ||
|
|
4b6dbf8887 | ||
|
|
06c99e1cc1 | ||
|
|
afb3e920f8 | ||
|
|
2c346c9850 | ||
|
|
5b6c5be288 | ||
|
|
63bd806222 | ||
|
|
afe3848b71 | ||
|
|
cd361ec7ec | ||
|
|
eb399fe799 | ||
|
|
53e588b6fc |
@@ -27,7 +27,7 @@ from flask import request
|
|||||||
|
|
||||||
class config_api:
|
class config_api:
|
||||||
|
|
||||||
__version = '0.15.2'
|
__version = '0.15.3'
|
||||||
__api_addr = 'data/api.json'
|
__api_addr = 'data/api.json'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ binlog-ignore-db = performance_schema
|
|||||||
|
|
||||||
#slave
|
#slave
|
||||||
log-slave-updates
|
log-slave-updates
|
||||||
|
slave_skip_errors=1062
|
||||||
#replicate-do-db
|
#replicate-do-db
|
||||||
replicate-ignore-db = information_schema
|
replicate-ignore-db = information_schema
|
||||||
replicate-ignore-db = performance_schema
|
replicate-ignore-db = performance_schema
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class='plugin_version'></div>
|
<div class='plugin_version'></div>
|
||||||
<div class="bt-w-main">
|
<div class="bt-w-main">
|
||||||
<div class="bt-w-menu">
|
<div class="bt-w-menu">
|
||||||
<script type="text/javascript">console.log($('.plugin_version').attr('version'));</script>
|
<!-- <script type="text/javascript">console.log($('.plugin_version').attr('version'));</script> -->
|
||||||
<p class="bgw" onclick="pluginService('mariadb', $('.plugin_version').attr('version'));">服务</p>
|
<p class="bgw" onclick="pluginService('mariadb', $('.plugin_version').attr('version'));">服务</p>
|
||||||
<p onclick="pluginInitD('mariadb', $('.plugin_version').attr('version'));">自启动</p>
|
<p onclick="pluginInitD('mariadb', $('.plugin_version').attr('version'));">自启动</p>
|
||||||
<p onclick="pluginConfig('mariadb', $('.plugin_version').attr('version'));">配置文件</p>
|
<p onclick="pluginConfig('mariadb', $('.plugin_version').attr('version'));">配置文件</p>
|
||||||
@@ -15,14 +15,12 @@
|
|||||||
<p onclick="dbList()">管理列表</p>
|
<p onclick="dbList()">管理列表</p>
|
||||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bt-w-con pd15">
|
<div class="bt-w-con pd15" style="height:555px;overflow: auto;">
|
||||||
<div class="soft-man-con"></div>
|
<div class="soft-man-con"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.db_list{
|
.db_list{
|
||||||
padding: 0px 0 10px 0;
|
padding: 0px 0 10px 0;
|
||||||
@@ -52,10 +50,7 @@
|
|||||||
</style>
|
</style>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
resetPluginWinWidth(800);
|
resetPluginWinWidth(800);
|
||||||
|
|
||||||
var loading = layer.msg("资源加载中...", { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
$.getScript( "/plugins/file?name=mariadb&f=js/mariadb.js", function(){
|
$.getScript( "/plugins/file?name=mariadb&f=js/mariadb.js", function(){
|
||||||
layer.close(loading);
|
|
||||||
pluginService('mariadb',$('.plugin_version').attr('version'));
|
pluginService('mariadb',$('.plugin_version').attr('version'));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
+258
-203
@@ -48,19 +48,19 @@ def getInitDFile():
|
|||||||
|
|
||||||
def getArgs():
|
def getArgs():
|
||||||
args = sys.argv[2:]
|
args = sys.argv[2:]
|
||||||
|
|
||||||
tmp = {}
|
tmp = {}
|
||||||
args_len = len(args)
|
args_len = len(args)
|
||||||
|
|
||||||
if args_len == 1:
|
if args_len == 1:
|
||||||
t = args[0].strip('{').strip('}')
|
t = args[0].strip('{').strip('}').strip()
|
||||||
|
if (t == ''):
|
||||||
|
return tmp
|
||||||
t = t.split(':')
|
t = t.split(':')
|
||||||
tmp[t[0]] = t[1]
|
tmp[t[0]] = t[1]
|
||||||
elif args_len > 1:
|
elif args_len > 1:
|
||||||
for i in range(len(args)):
|
for i in range(len(args)):
|
||||||
t = args[i].split(':')
|
t = args[i].split(':')
|
||||||
tmp[t[0]] = t[1]
|
tmp[t[0]] = t[1]
|
||||||
|
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
|
||||||
@@ -107,6 +107,14 @@ def getDbPort():
|
|||||||
return tmp.groups()[0].strip()
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
|
def getDbServerId():
|
||||||
|
file = getConf()
|
||||||
|
content = mw.readFile(file)
|
||||||
|
rep = 'server-id\s*=\s*(.*)'
|
||||||
|
tmp = re.search(rep, content)
|
||||||
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
def getSocketFile():
|
def getSocketFile():
|
||||||
file = getConf()
|
file = getConf()
|
||||||
content = mw.readFile(file)
|
content = mw.readFile(file)
|
||||||
@@ -664,15 +672,15 @@ def isSqlError(mysqlMsg):
|
|||||||
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||||
if "using password:" in mysqlMsg:
|
if "using password:" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
||||||
if "1045" in mysqlMsg:
|
if "1045," in mysqlMsg:
|
||||||
return mw.returnJson(False, '连接错误!')
|
return mw.returnJson(False, '连接错误!')
|
||||||
if "SQL syntax" in mysqlMsg:
|
if "SQL syntax" in mysqlMsg:
|
||||||
return mw.returnJson(False, 'SQL语法错误!')
|
return mw.returnJson(False, 'SQL语法错误!')
|
||||||
if "Connection refused" in mysqlMsg:
|
if "Connection refused" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||||
if "1133" in mysqlMsg:
|
if "1133," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库用户不存在!')
|
return mw.returnJson(False, '数据库用户不存在!')
|
||||||
if "1007" in mysqlMsg:
|
if "1007," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库已经存在!')
|
return mw.returnJson(False, '数据库已经存在!')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -940,7 +948,7 @@ def getDbList():
|
|||||||
|
|
||||||
|
|
||||||
def syncGetDatabases():
|
def syncGetDatabases():
|
||||||
pdb = pMysqlDb()
|
pdb = pMysqlDb('mysql')
|
||||||
psdb = pSqliteDb('databases')
|
psdb = pSqliteDb('databases')
|
||||||
data = pdb.query('show databases')
|
data = pdb.query('show databases')
|
||||||
isError = isSqlError(data)
|
isError = isSqlError(data)
|
||||||
@@ -1706,12 +1714,14 @@ def getMasterStatus(version=''):
|
|||||||
data['mode'] = recognizeDbMode()
|
data['mode'] = recognizeDbMode()
|
||||||
data['status'] = master_status
|
data['status'] = master_status
|
||||||
|
|
||||||
db = pMysqlDb()
|
pdb = pMysqlDb('mysql')
|
||||||
dlist = db.query('show slave status')
|
dlist = pdb.query('show slave status')
|
||||||
|
if len(dlist) < 1:
|
||||||
|
dlist = pdb.query("show all slaves status")
|
||||||
|
|
||||||
# print(dlist[0])
|
for v in dlist:
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
if v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes':
|
||||||
data['slave_status'] = True
|
data['slave_status'] = True
|
||||||
|
|
||||||
return mw.returnJson(master_status, '设置成功', data)
|
return mw.returnJson(master_status, '设置成功', data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1855,6 +1865,9 @@ def getMasterRepSlaveUserCmd(version):
|
|||||||
clist = psdb.field(f).where("username=?", (username,)).limit(
|
clist = psdb.field(f).where("username=?", (username,)).limit(
|
||||||
'1').order('id desc').select()
|
'1').order('id desc').select()
|
||||||
|
|
||||||
|
if len(clist) == 0:
|
||||||
|
return mw.returnJson(False, '错误同步账户!')
|
||||||
|
|
||||||
ip = mw.getLocalIp()
|
ip = mw.getLocalIp()
|
||||||
port = getMyPort()
|
port = getMyPort()
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
@@ -1868,15 +1881,23 @@ def getMasterRepSlaveUserCmd(version):
|
|||||||
# 查找同步点
|
# 查找同步点
|
||||||
# SELECT BINLOG_GTID_POS('master1-bin.000002', 561866201);
|
# SELECT BINLOG_GTID_POS('master1-bin.000002', 561866201);
|
||||||
|
|
||||||
|
sid = getDbServerId()
|
||||||
|
connection_name = ""
|
||||||
|
if sid != '':
|
||||||
|
connection_name = "'r{}' ".format(sid)
|
||||||
|
|
||||||
|
# MASTER_USE_GTID={current_pos|slave_pos|no}
|
||||||
|
# current_pos 依赖-> select @@global.gtid_current_pos;
|
||||||
|
# slave_pos 依赖-> select @@global.gtid_slave_pos;
|
||||||
|
# no -> 啥都不依赖,保证多主同步成功。同步出现问题,根据日志查找问题。
|
||||||
|
|
||||||
if mode == "gtid":
|
if mode == "gtid":
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', " + "MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
clist[0]['password'] + "', " + "MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',MASTER_LOG_POS=" + \
|
"',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
|
||||||
str(mstatus[0]["Position"]) + \
|
|
||||||
",MASTER_USE_GTID=slave_pos,MASTER_CONNECT_RETRY=10;"
|
|
||||||
else:
|
else:
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
@@ -2151,48 +2172,20 @@ def updateSlaveSSH(version=''):
|
|||||||
|
|
||||||
|
|
||||||
def getSlaveList(version=''):
|
def getSlaveList(version=''):
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
ret = []
|
if len(dlist) == 0:
|
||||||
for x in range(0, len(dlist)):
|
dlist = db.query('show all slaves status')
|
||||||
tmp = {}
|
|
||||||
tmp['Master_User'] = dlist[x]["Master_User"]
|
|
||||||
tmp['Master_Host'] = dlist[x]["Master_Host"]
|
|
||||||
tmp['Master_Port'] = dlist[x]["Master_Port"]
|
|
||||||
tmp['Master_Log_File'] = dlist[x]["Master_Log_File"]
|
|
||||||
tmp['Slave_IO_Running'] = dlist[x]["Slave_IO_Running"]
|
|
||||||
tmp['Slave_SQL_Running'] = dlist[x]["Slave_SQL_Running"]
|
|
||||||
tmp['Last_Error'] = dlist[x]["Last_Error"]
|
|
||||||
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
|
|
||||||
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
|
|
||||||
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
|
|
||||||
|
|
||||||
tmp['Error'] = ''
|
|
||||||
if tmp['Last_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_Error']
|
|
||||||
|
|
||||||
if tmp['Last_IO_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_IO_Error']
|
|
||||||
|
|
||||||
if tmp['Last_SQL_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_SQL_Error']
|
|
||||||
|
|
||||||
if tmp['Error'] == '':
|
|
||||||
tmp['Error'] = tmp['Slave_SQL_Running_State']
|
|
||||||
|
|
||||||
ret.append(tmp)
|
|
||||||
data = {}
|
data = {}
|
||||||
data['data'] = ret
|
data['data'] = dlist
|
||||||
|
|
||||||
return mw.getJson(data)
|
return mw.getJson(data)
|
||||||
|
|
||||||
|
|
||||||
def getSlaveSyncCmd(version=''):
|
def getSlaveSyncCmd(version=''):
|
||||||
|
|
||||||
root = mw.getRunDir()
|
root = mw.getRunDir()
|
||||||
cmd = 'cd ' + root + ' && python3 ' + root + \
|
cmd = 'cd ' + root + ' && python3 ' + root + \
|
||||||
'/plugins/mysql/index.py do_full_sync {"db":"all"}'
|
'/plugins/mariadb/index.py do_full_sync {"db":"all","sign":""}'
|
||||||
return mw.returnJson(True, 'ok', cmd)
|
return mw.returnJson(True, 'ok', cmd)
|
||||||
|
|
||||||
|
|
||||||
@@ -2208,102 +2201,151 @@ def initSlaveStatus(version=''):
|
|||||||
return initSlaveStatusSyncUser(version)
|
return initSlaveStatusSyncUser(version)
|
||||||
|
|
||||||
|
|
||||||
|
def parseSlaveSyncCmd(cmd):
|
||||||
|
a = {}
|
||||||
|
vlist = cmd.split(',')
|
||||||
|
|
||||||
|
has_connection_name = vlist[0]
|
||||||
|
|
||||||
|
pattern_c = r"CHANGE MASTER \'(.*)\' TO MASTER_HOST"
|
||||||
|
match_val = re.match(pattern_c, has_connection_name, re.I)
|
||||||
|
if match_val:
|
||||||
|
m_groups = match_val.groups()
|
||||||
|
a['Connection_name'] = m_groups[0]
|
||||||
|
|
||||||
|
for i in vlist:
|
||||||
|
tmp = i.strip()
|
||||||
|
tmp_a = tmp.split(" ")
|
||||||
|
real_tmp = tmp_a[len(tmp_a) - 1]
|
||||||
|
kv = real_tmp.split("=")
|
||||||
|
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSyncUser(version=''):
|
def initSlaveStatusSyncUser(version=''):
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
|
||||||
if len(data) < 1:
|
slave_data = conn.field('id,ip,port,user,pass,mode,cmd').select()
|
||||||
|
if len(slave_data) < 1:
|
||||||
return mw.returnJson(False, '需要先添加同步用户配置!')
|
return mw.returnJson(False, '需要先添加同步用户配置!')
|
||||||
|
|
||||||
# print(data)
|
pdb = pMysqlDb()
|
||||||
db = pMysqlDb()
|
if len(slave_data) == 1:
|
||||||
dlist = db.query('show slave status')
|
dlist = pdb.query('show slave status')
|
||||||
if len(dlist) > 0:
|
if len(dlist) > 0:
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
return mw.returnJson(False, '已经初始化好了zz...')
|
||||||
|
|
||||||
u = data
|
msg = ''
|
||||||
|
|
||||||
mode_name = 'classic'
|
pdb.query("stop slave")
|
||||||
if u['mode'] == '1':
|
pdb.query("stop all slaves")
|
||||||
mode_name = 'gtid'
|
|
||||||
|
|
||||||
local_mode = recognizeDbMode()
|
local_mode = recognizeDbMode()
|
||||||
if local_mode != mode_name:
|
for x in range(len(slave_data)):
|
||||||
return mw.returnJson(False, '同步模式不一致!')
|
slave_t = slave_data[x]
|
||||||
|
base_t = 'IP:' + slave_t['ip'] + ",PORT:" + \
|
||||||
|
slave_t['port'] + ",USER:" + slave_t['user']
|
||||||
|
|
||||||
# print(u['cmd'])
|
mode_name = 'classic'
|
||||||
t = db.query(u['cmd'])
|
if slave_data[x]['mode'] == '1':
|
||||||
# print(t)
|
mode_name = 'gtid'
|
||||||
db.query("start slave")
|
|
||||||
return mw.returnJson(True, '初始化成功!')
|
if local_mode != mode_name:
|
||||||
|
msg += base_t + '->同步模式不一致'
|
||||||
|
continue
|
||||||
|
|
||||||
|
cmd_sql = slave_t['cmd']
|
||||||
|
if cmd_sql == '':
|
||||||
|
msg += base_t + '->同步命令不能为空'
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
pinfo = parseSlaveSyncCmd(cmd_sql)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
|
||||||
|
|
||||||
|
pdb.query(cmd_sql)
|
||||||
|
|
||||||
|
pdb.query("start slave")
|
||||||
|
pdb.query("start all slaves ")
|
||||||
|
|
||||||
|
if msg == '':
|
||||||
|
msg = '初始化成功!'
|
||||||
|
return mw.returnJson(True, msg)
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSSH(version=''):
|
def initSlaveStatusSSH(version=''):
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
if len(dlist) > 0:
|
if len(dlist) == 0:
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
dlist = db.query('show all slaves status')
|
||||||
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
conn = pSqliteDb('slave_id_rsa')
|
||||||
data = conn.field('ip,port,id_rsa,db_user').find()
|
ssh_list = conn.field('ip,port,id_rsa,db_user').select()
|
||||||
|
|
||||||
if len(data) < 1:
|
if len(ssh_list) < 1:
|
||||||
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
|
|
||||||
ip = data['ip']
|
|
||||||
master_port = data['port']
|
|
||||||
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
paramiko.util.log_to_file('paramiko.log')
|
paramiko.util.log_to_file('paramiko.log')
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
|
|
||||||
try:
|
for data in ssh_list:
|
||||||
|
ip = data['ip']
|
||||||
|
master_port = data['port']
|
||||||
|
SSH_PRIVATE_KEY = "/tmp/t_ssh_" + ip + ".txt"
|
||||||
|
|
||||||
|
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
||||||
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
||||||
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
||||||
ssh.connect(hostname=ip, port=int(master_port),
|
|
||||||
username='root', pkey=key)
|
|
||||||
|
|
||||||
db_user = data['db_user']
|
try:
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
result = stdout.read()
|
ssh.connect(hostname=ip, port=int(master_port),
|
||||||
result = result.decode('utf-8')
|
username='root', pkey=key)
|
||||||
cmd_data = json.loads(result)
|
|
||||||
time.sleep(1)
|
|
||||||
ssh.close()
|
|
||||||
if not cmd_data['status']:
|
|
||||||
return mw.returnJson(False, '[主]:' + cmd_data['msg'])
|
|
||||||
|
|
||||||
local_mode = recognizeDbMode()
|
db_user = data['db_user']
|
||||||
if local_mode != cmd_data['data']['mode']:
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
||||||
return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
|
result = stdout.read()
|
||||||
|
result = result.decode('utf-8')
|
||||||
|
if result.strip() == "":
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:获取同步命令失败!')
|
||||||
|
cmd_data = json.loads(result)
|
||||||
|
time.sleep(1)
|
||||||
|
ssh.close()
|
||||||
|
if not cmd_data['status']:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg'])
|
||||||
|
|
||||||
u = cmd_data['data']['info']
|
local_mode = recognizeDbMode()
|
||||||
ps = u['username'] + "|" + u['password']
|
if local_mode != cmd_data['data']['mode']:
|
||||||
conn.where('ip=?', (ip,)).setField('ps', ps)
|
return mw.returnJson(False, '[主][' + ip + ']【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
||||||
db.query('stop slave')
|
|
||||||
|
|
||||||
# 保证同步IP一致
|
u = cmd_data['data']['info']
|
||||||
cmd = cmd_data['data']['cmd']
|
ps = u['username'] + "|" + u['password']
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
conn.where('ip=?', (ip,)).setField('ps', ps)
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
db.query('stop slave')
|
||||||
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
db.query('stop all slaves')
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
# 保证同步IP一致
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
cmd = cmd_data['data']['cmd']
|
||||||
"MASTER_HOST='" + ip + "'", cmd, 1)
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
# print(cmd)
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
db.query(cmd)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
db.query("start slave")
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
except Exception as e:
|
# print(cmd)
|
||||||
return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e))
|
db.query(cmd)
|
||||||
|
db.query("start slave")
|
||||||
|
db.query("start all slaves")
|
||||||
|
if os.path.exists(SSH_PRIVATE_KEY):
|
||||||
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:SSH认证配置连接失败!' + str(e))
|
||||||
|
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
|
||||||
return mw.returnJson(True, '初始化成功!')
|
return mw.returnJson(True, '初始化成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2312,61 +2354,39 @@ def setSlaveStatus(version=''):
|
|||||||
if not os.path.exists(mode_file):
|
if not os.path.exists(mode_file):
|
||||||
return mw.returnJson(False, '需要先设置同步配置')
|
return mw.returnJson(False, '需要先设置同步配置')
|
||||||
|
|
||||||
mode = mw.readFile(mode_file)
|
pdb = pMysqlDb()
|
||||||
if mode == 'ssh':
|
dlist = pdb.query('show slave status')
|
||||||
return setSlaveStatusSSH(version)
|
if len(dlist) == 0:
|
||||||
if mode == 'sync-user':
|
dlist = pdb.query('show all slaves status')
|
||||||
return setSlaveStatusSyncUser(version)
|
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSyncUser(version=''):
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
if len(dlist) == 0:
|
||||||
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
for v in dlist:
|
||||||
db.query('stop slave')
|
connection_name = ''
|
||||||
else:
|
cmd = "slave"
|
||||||
ip = dlist[0]['Master_Host']
|
if 'Connection_name' in v:
|
||||||
conn = pSqliteDb('slave_sync_user')
|
connection_name = v['Connection_name']
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
cmd = "slave '{}'".format(connection_name)
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
user = data['user']
|
|
||||||
apass = data['pass']
|
|
||||||
|
|
||||||
db.query("start slave")
|
if (v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes'):
|
||||||
# db.query("start slave user='{}' password='{}';".format(user, apass))
|
pdb.query("stop {}".format(cmd))
|
||||||
|
else:
|
||||||
return mw.returnJson(True, '设置成功!')
|
pdb.query("start {}".format(cmd))
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSSH(version=''):
|
|
||||||
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
|
||||||
return mw.returnJson(False, '需要手动添加主服务命令或者执行[初始化]!')
|
|
||||||
|
|
||||||
# print(dlist)
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
|
||||||
db.query('stop slave')
|
|
||||||
else:
|
|
||||||
ip = dlist[0]['Master_Host']
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
|
||||||
data = conn.field('ip,ps').where("ip=?", (ip,)).find()
|
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
db.query("start slave")
|
|
||||||
|
|
||||||
return mw.returnJson(True, '设置成功!')
|
return mw.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
|
||||||
def deleteSlave(version=''):
|
def deleteSlave(version=''):
|
||||||
|
args = getArgs()
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('stop slave')
|
if 'sign' in args:
|
||||||
dlist = db.query('reset slave all')
|
sign = args['sign']
|
||||||
|
db.query("stop slave '{}'".format(sign))
|
||||||
|
db.query("reset slave '{}' all".format(sign))
|
||||||
|
else:
|
||||||
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
return mw.returnJson(True, '删除成功!')
|
return mw.returnJson(True, '删除成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2402,14 +2422,54 @@ def dumpMysqlData(version=''):
|
|||||||
|
|
||||||
############### --- 重要 同步---- ###########
|
############### --- 重要 同步---- ###########
|
||||||
|
|
||||||
|
|
||||||
|
def asyncTmpfile():
|
||||||
|
path = '/tmp/mariadb_async_status.txt'
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def writeDbSyncStatus(data):
|
def writeDbSyncStatus(data):
|
||||||
path = '/tmp/db_async_status.txt'
|
path = asyncTmpfile()
|
||||||
# status_data['code'] = 1
|
|
||||||
# status_data['msg'] = '主服务器备份完成...'
|
|
||||||
# status_data['progress'] = 30
|
|
||||||
mw.writeFile(path, json.dumps(data))
|
mw.writeFile(path, json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
def fullSync(version=''):
|
||||||
|
args = getArgs()
|
||||||
|
data = checkArgs(args, ['db', 'begin'])
|
||||||
|
if not data[0]:
|
||||||
|
return data[1]
|
||||||
|
|
||||||
|
sign = ''
|
||||||
|
if 'sign' in args:
|
||||||
|
sign = args['sign']
|
||||||
|
|
||||||
|
status_file = asyncTmpfile()
|
||||||
|
if args['begin'] == '1':
|
||||||
|
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
||||||
|
getPluginDir() + \
|
||||||
|
'/index.py do_full_sync {"db":"' + \
|
||||||
|
args['db'] + '","sign":"' + sign + '"} &'
|
||||||
|
# print(cmd)
|
||||||
|
mw.execShell(cmd)
|
||||||
|
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
||||||
|
|
||||||
|
if os.path.exists(status_file):
|
||||||
|
c = mw.readFile(status_file)
|
||||||
|
tmp = json.loads(c)
|
||||||
|
if tmp['code'] == 1:
|
||||||
|
sys_dump_sql = "/tmp/dump.sql"
|
||||||
|
if os.path.exists(sys_dump_sql):
|
||||||
|
dump_size = os.path.getsize(sys_dump_sql)
|
||||||
|
tmp['msg'] = tmp['msg'] + ":" + "同步文件:" + mw.toSize(dump_size)
|
||||||
|
c = json.dumps(tmp)
|
||||||
|
|
||||||
|
# if tmp['code'] == 6:
|
||||||
|
# os.remove(status_file)
|
||||||
|
return c
|
||||||
|
|
||||||
|
return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
|
||||||
|
|
||||||
|
|
||||||
def doFullSync(version=''):
|
def doFullSync(version=''):
|
||||||
mode_file = getSyncModeFile()
|
mode_file = getSyncModeFile()
|
||||||
if not os.path.exists(mode_file):
|
if not os.path.exists(mode_file):
|
||||||
@@ -2424,16 +2484,23 @@ def doFullSync(version=''):
|
|||||||
|
|
||||||
def doFullSyncUser(version=''):
|
def doFullSyncUser(version=''):
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
sync_db = args['db']
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
|
# print(sync_sign, sync_db)
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
if sync_sign != '':
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
||||||
|
|
||||||
user = data['user']
|
user = data['user']
|
||||||
apass = data['pass']
|
apass = data['pass']
|
||||||
port = data['port']
|
port = data['port']
|
||||||
@@ -2442,12 +2509,12 @@ def doFullSyncUser(version=''):
|
|||||||
bak_file = '/tmp/tmp.sql'
|
bak_file = '/tmp/tmp.sql'
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
|
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
|
||||||
|
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 10})
|
||||||
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
|
|
||||||
|
|
||||||
if not os.path.exists(bak_file):
|
if not os.path.exists(bak_file):
|
||||||
dump_sql_data = getServerDir() + "/bin/mysqldump --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
|
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
|
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
|
||||||
|
print(dump_sql_data)
|
||||||
mw.execShell(dump_sql_data)
|
mw.execShell(dump_sql_data)
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
||||||
@@ -2458,24 +2525,38 @@ def doFullSyncUser(version=''):
|
|||||||
' ' + sync_db + ' < ' + bak_file
|
' ' + sync_db + ' < ' + bak_file
|
||||||
mw.execShell(my_import_cmd)
|
mw.execShell(my_import_cmd)
|
||||||
|
|
||||||
db.query("start slave")
|
pinfo = parseSlaveSyncCmd(data['cmd'])
|
||||||
|
# print(pinfo)
|
||||||
|
if 'Connection_name' in pinfo:
|
||||||
|
db.query("start slave '{}'".format(pinfo['Connection_name']))
|
||||||
|
else:
|
||||||
|
db.query("start slave")
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
os.system("rm -rf " + bak_file)
|
|
||||||
|
if os.path.exists(bak_file):
|
||||||
|
os.system("rm -rf " + bak_file)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def doFullSyncSSH(version=''):
|
def doFullSyncSSH(version=''):
|
||||||
|
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
||||||
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
if sync_sign != '':
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
||||||
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
||||||
@@ -2498,7 +2579,6 @@ def doFullSyncSSH(version=''):
|
|||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# ssh.load_system_host_keys()
|
|
||||||
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
||||||
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
@@ -2516,7 +2596,7 @@ def doFullSyncSSH(version=''):
|
|||||||
|
|
||||||
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
||||||
dbname = args['db']
|
dbname = args['db']
|
||||||
cmd = "cd /www/server/mdserver-web && python3 plugins/mariadb/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
cmd = "cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
||||||
print(cmd)
|
print(cmd)
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
@@ -2539,13 +2619,19 @@ def doFullSyncSSH(version=''):
|
|||||||
if copy_status == None:
|
if copy_status == None:
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
result = result.decode('utf-8')
|
result = result.decode('utf-8')
|
||||||
|
|
||||||
|
if result == '':
|
||||||
|
writeDbSyncStatus({'code': 1, 'msg': '同步命令获取失败!', 'progress': 100})
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
cmd_data = json.loads(result)
|
cmd_data = json.loads(result)
|
||||||
|
|
||||||
db.query('stop slave')
|
db.query('stop slave')
|
||||||
|
db.query('stop all slaves')
|
||||||
writeDbSyncStatus({'code': 3, 'msg': '停止从库完成...', 'progress': 45})
|
writeDbSyncStatus({'code': 3, 'msg': '停止从库完成...', 'progress': 45})
|
||||||
|
|
||||||
cmd = cmd_data['data']['cmd']
|
cmd = cmd_data['data']['cmd']
|
||||||
@@ -2578,6 +2664,7 @@ def doFullSyncSSH(version=''):
|
|||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
db.query("start slave")
|
db.query("start slave")
|
||||||
|
db.query("start all slaves")
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
|
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
@@ -2585,38 +2672,6 @@ def doFullSyncSSH(version=''):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def fullSync(version=''):
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['db', 'begin'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
status_file = '/tmp/db_async_status.txt'
|
|
||||||
if args['begin'] == '1':
|
|
||||||
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
|
||||||
getPluginDir() + \
|
|
||||||
'/index.py do_full_sync {"db":"' + args['db'] + '"} &'
|
|
||||||
print(cmd)
|
|
||||||
mw.execShell(cmd)
|
|
||||||
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
|
||||||
|
|
||||||
if os.path.exists(status_file):
|
|
||||||
c = mw.readFile(status_file)
|
|
||||||
tmp = json.loads(c)
|
|
||||||
if tmp['code'] == 1:
|
|
||||||
sys_dump_sql = "/tmp/dump.sql"
|
|
||||||
if os.path.exists(sys_dump_sql):
|
|
||||||
dump_size = os.path.getsize(sys_dump_sql)
|
|
||||||
tmp['msg'] = tmp['msg'] + ":" + "同步文件:" + mw.toSize(dump_size)
|
|
||||||
c = json.dumps(tmp)
|
|
||||||
|
|
||||||
# if tmp['code'] == 6:
|
|
||||||
# os.remove(status_file)
|
|
||||||
return c
|
|
||||||
|
|
||||||
return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
|
|
||||||
|
|
||||||
|
|
||||||
def installPreInspection(version):
|
def installPreInspection(version):
|
||||||
swap_path = mw.getServerDir() + "/swap"
|
swap_path = mw.getServerDir() + "/swap"
|
||||||
if not os.path.exists(swap_path):
|
if not os.path.exists(swap_path):
|
||||||
|
|||||||
+178
-86
@@ -431,7 +431,6 @@ function syncToDatabase(type){
|
|||||||
var postData = 'type='+type+'&ids='+JSON.stringify(data);
|
var postData = 'type='+type+'&ids='+JSON.stringify(data);
|
||||||
myPost('sync_to_databases', postData, function(data){
|
myPost('sync_to_databases', postData, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
// console.log(rdata);
|
|
||||||
showMsg(rdata.msg,function(){
|
showMsg(rdata.msg,function(){
|
||||||
dbList();
|
dbList();
|
||||||
},{ icon: rdata.status ? 1 : 2 });
|
},{ icon: rdata.status ? 1 : 2 });
|
||||||
@@ -439,18 +438,6 @@ function syncToDatabase(type){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setRootPwd(type, pwd){
|
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();
|
|
||||||
$('.layui-layer-close1').click();
|
|
||||||
},{icon: rdata.status ? 1 : 2});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = layer.open({
|
var index = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
area: '500px',
|
area: '500px',
|
||||||
@@ -467,8 +454,16 @@ function setRootPwd(type, pwd){
|
|||||||
</div>\
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</form>",
|
</form>",
|
||||||
yes:function(){
|
yes:function(index,layero){
|
||||||
setRootPwd(1);
|
var password = $("#MyPassword").val();
|
||||||
|
myPost('set_root_pwd', {password:password}, function(data){
|
||||||
|
var rdata = $.parseJSON(data.data);
|
||||||
|
showMsg(rdata.msg,function(){
|
||||||
|
dbList();
|
||||||
|
layer.close(index);
|
||||||
|
},{icon: rdata.status ? 1 : 2});
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -490,7 +485,6 @@ function showHidePass(obj){
|
|||||||
function checkSelect(){
|
function checkSelect(){
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
var num = $('input[type="checkbox"].check:checked').length;
|
var num = $('input[type="checkbox"].check:checked').length;
|
||||||
// console.log(num);
|
|
||||||
if (num == 1) {
|
if (num == 1) {
|
||||||
$('button[batch="true"]').hide();
|
$('button[batch="true"]').hide();
|
||||||
$('button[batch="false"]').show();
|
$('button[batch="false"]').show();
|
||||||
@@ -861,7 +855,6 @@ function downloadBackup(file){
|
|||||||
|
|
||||||
function importBackup(file,name){
|
function importBackup(file,name){
|
||||||
myPost('import_db_backup',{file:file,name:name}, function(data){
|
myPost('import_db_backup',{file:file,name:name}, function(data){
|
||||||
// console.log(data);
|
|
||||||
layer.msg('执行成功!');
|
layer.msg('执行成功!');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1619,7 +1612,6 @@ function getMasterRepSlaveList(){
|
|||||||
_data['page'] = page;
|
_data['page'] = page;
|
||||||
_data['page_size'] = 10;
|
_data['page_size'] = 10;
|
||||||
myPost('get_master_rep_slave_list', _data, function(data){
|
myPost('get_master_rep_slave_list', _data, function(data){
|
||||||
// console.log(data);
|
|
||||||
var rdata = [];
|
var rdata = [];
|
||||||
try {
|
try {
|
||||||
rdata = $.parseJSON(data.data);
|
rdata = $.parseJSON(data.data);
|
||||||
@@ -1672,12 +1664,12 @@ function getMasterRepSlaveListPage(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteSlave(){
|
function deleteSlave(sign = ''){
|
||||||
myPost('delete_slave', {}, function(data){
|
myPost('delete_slave', {sign:sign}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
showMsg(rdata['msg'], function(){
|
showMsg(rdata['msg'], function(){
|
||||||
masterOrSlaveConf();
|
masterOrSlaveConf();
|
||||||
},{},3000);
|
},{icon:rdata.status?1:2,time:3000},3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1685,28 +1677,72 @@ function deleteSlave(){
|
|||||||
function getFullSyncStatus(db){
|
function getFullSyncStatus(db){
|
||||||
var timeId = null;
|
var timeId = null;
|
||||||
|
|
||||||
var btn = '<div class="table_toolbar" style="left:0px;"><span data-status="init" class="sync btn btn-default btn-sm" id="begin_full_sync" title="">开始</span></div>';
|
myPost('get_slave_list', {page:1,page_size:100}, function(data){
|
||||||
var loadOpen = layer.open({
|
var rdata = $.parseJSON(data.data);
|
||||||
type: 1,
|
var rsource = rdata.data;
|
||||||
title: '全量同步['+db+']',
|
|
||||||
area: '500px',
|
if (db == 'ALL' && rsource.length>1){
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
layer.msg("多主不支持该模式!",{icon:2});
|
||||||
<div class='divtable mtb10'>\
|
return;
|
||||||
<span id='full_msg'></span>\
|
|
||||||
<div class='progress'>\
|
|
||||||
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
"+btn+"\
|
|
||||||
</div>",
|
|
||||||
cancel: function(){
|
|
||||||
clearInterval(timeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dataSource = '';
|
||||||
|
if (rsource.length>1){
|
||||||
|
var sourceList = '';
|
||||||
|
for (var i = 0; i < rsource.length; i++) {
|
||||||
|
if ('Connection_name' in rsource[i]){
|
||||||
|
sourceList += '<option val="'+rsource[i]['Master_Host']+'">'+rsource[i]['Master_Host']+'</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource = "<p class='line' style='text-align:center;'>\
|
||||||
|
<span>同步数据源:</span>\
|
||||||
|
<select class='bt-input-text' name='data_source' style='width:200px;'>" + sourceList + "</select>\
|
||||||
|
</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '全量同步['+db+']',
|
||||||
|
area: '500px',
|
||||||
|
content:"<div class='bt-form pd15'>\
|
||||||
|
<div class='divtable mtb10'>\
|
||||||
|
"+dataSource+"\
|
||||||
|
<span id='full_msg'></span>\
|
||||||
|
<div class='progress'>\
|
||||||
|
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class='table_toolbar' style='left:0px;'>\
|
||||||
|
<span data-status='init' class='sync btn btn-default btn-sm' id='begin_full_sync'>开始</span>\
|
||||||
|
</div>\
|
||||||
|
</div>",
|
||||||
|
cancel: function(){
|
||||||
|
clearInterval(timeId);
|
||||||
|
},
|
||||||
|
success:function(){
|
||||||
|
$('#begin_full_sync').click(function(){
|
||||||
|
var val = $(this).data('status');
|
||||||
|
var sign = '';
|
||||||
|
if (dataSource !=''){
|
||||||
|
sign = $('select[name="data_source"]').val();
|
||||||
|
}
|
||||||
|
if (val == 'init'){
|
||||||
|
fullSync(db, sign, 1);
|
||||||
|
timeId = setInterval(function(){
|
||||||
|
fullSync(db,sign,0);
|
||||||
|
}, 1000);
|
||||||
|
$(this).data('status','starting');
|
||||||
|
} else {
|
||||||
|
layer.msg("正在同步中..",{icon:0});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function fullSync(db,begin){
|
function fullSync(db, sign, begin){
|
||||||
|
myPostN('full_sync', {db:db,sign:sign,begin:begin}, function(data){
|
||||||
myPostN('full_sync', {db:db,begin:begin}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
$('#full_msg').text(rdata['msg']);
|
$('#full_msg').text(rdata['msg']);
|
||||||
$('.progress-bar').css('width',rdata['progress']+'%');
|
$('.progress-bar').css('width',rdata['progress']+'%');
|
||||||
@@ -1715,23 +1751,11 @@ function getFullSyncStatus(db){
|
|||||||
if (rdata['code']==6 ||rdata['code']<0){
|
if (rdata['code']==6 ||rdata['code']<0){
|
||||||
layer.msg(rdata['msg']);
|
layer.msg(rdata['msg']);
|
||||||
clearInterval(timeId);
|
clearInterval(timeId);
|
||||||
$("#begin_full_sync").attr('data-status','init');
|
$("#begin_full_sync").data('status','init');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#begin_full_sync').click(function(){
|
|
||||||
var val = $(this).attr('data-status');
|
|
||||||
if (val == 'init'){
|
|
||||||
fullSync(db,1);
|
|
||||||
timeId = setInterval(function(){
|
|
||||||
fullSync(db,0);
|
|
||||||
}, 1000);
|
|
||||||
$(this).attr('data-status','starting');
|
|
||||||
} else {
|
|
||||||
layer.msg("正在同步中..");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSlaveSSH(ip=''){
|
function addSlaveSSH(ip=''){
|
||||||
@@ -2077,7 +2101,7 @@ function getSlaveUserList(){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步账户列表',
|
title: '同步账户列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2101,7 +2125,7 @@ function getSlaveSSHList(page=1){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: 'SSH列表',
|
title: 'SSH列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2142,11 +2166,15 @@ function handlerRun(){
|
|||||||
function initSlaveStatus(){
|
function initSlaveStatus(){
|
||||||
myPost('init_slave_status', '', function(data){
|
myPost('init_slave_status', '', function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
|
if (!rdata.status ){
|
||||||
|
layer.msg(rdata.msg,{icon:2,time:10000});
|
||||||
|
return;
|
||||||
|
}
|
||||||
showMsg(rdata.msg,function(){
|
showMsg(rdata.msg,function(){
|
||||||
if (rdata.status){
|
if (rdata.status){
|
||||||
masterOrSlaveConf();
|
masterOrSlaveConf();
|
||||||
}
|
}
|
||||||
},{icon:rdata.status?1:2},2000);
|
},{icon:1},2000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2204,33 +2232,48 @@ function masterOrSlaveConf(version=''){
|
|||||||
}
|
}
|
||||||
|
|
||||||
_data['page'] = page;
|
_data['page'] = page;
|
||||||
_data['page_size'] = 10;
|
_data['page_size'] = 100;
|
||||||
|
|
||||||
myPost('get_slave_list', _data, function(data){
|
myPost('get_slave_list', _data, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
var list = '';
|
var list = '';
|
||||||
|
|
||||||
|
var isHasSign = false;
|
||||||
for(i in rdata.data){
|
for(i in rdata.data){
|
||||||
|
|
||||||
var v = rdata.data[i];
|
var v = rdata.data[i];
|
||||||
var status = "<a class='btlink db_error'>异常</>";
|
if ('Connection_name' in v){
|
||||||
|
isHasSign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = "<a data-id="+i+" class='btlink db_error'>异常</>";
|
||||||
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
||||||
status = "正常";
|
status = "正常";
|
||||||
}
|
}
|
||||||
|
|
||||||
list += '<tr>';
|
list += '<tr>';
|
||||||
list += '<td>' + rdata.data[i]['Master_Host'] +'</td>';
|
list += '<td>' + v['Master_Host'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Master_Port'] +'</td>';
|
list += '<td>' + v['Master_Port'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Master_User'] +'</td>';
|
list += '<td>' + v['Master_User'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
list += '<td>' + v['Master_Log_File'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
list += '<td>' + v['Slave_IO_Running'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
list += '<td>' + v['Slave_SQL_Running'] +'</td>';
|
||||||
|
if (isHasSign){
|
||||||
|
list += '<td>' + v['Connection_name'] +'</td>';
|
||||||
|
}
|
||||||
|
|
||||||
list += '<td>' + status +'</td>';
|
list += '<td>' + status +'</td>';
|
||||||
list += '<td style="text-align:right">' +
|
list += '<td style="text-align:right">\
|
||||||
'<a href="javascript:;" class="btlink" onclick="deleteSlave()" title="删除">删除</a>' +
|
<a data-id="'+i+'" href="javascript:;" class="btlink btn_delete_slave" title="删除">删除</a>\
|
||||||
'</td>';
|
</td>';
|
||||||
list += '</tr>';
|
list += '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var signThead_th = '';
|
||||||
|
if (isHasSign){
|
||||||
|
var signThead_th = '<th>标识</th>';
|
||||||
|
}
|
||||||
|
|
||||||
var con = '<div class="divtable mtb10">\
|
var con = '<div class="divtable mtb10">\
|
||||||
<div class="tablescroll">\
|
<div class="tablescroll">\
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||||
@@ -2241,6 +2284,7 @@ function masterOrSlaveConf(version=''){
|
|||||||
<th>日志</th>\
|
<th>日志</th>\
|
||||||
<th>IO</th>\
|
<th>IO</th>\
|
||||||
<th>SQL</th>\
|
<th>SQL</th>\
|
||||||
|
'+signThead_th+'\
|
||||||
<th>状态</th>\
|
<th>状态</th>\
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
<th style="text-align:right;">操作</th></tr></thead>\
|
||||||
<tbody>\
|
<tbody>\
|
||||||
@@ -2255,22 +2299,75 @@ function masterOrSlaveConf(version=''){
|
|||||||
// </div>
|
// </div>
|
||||||
$(".table_slave_status_list").html(con);
|
$(".table_slave_status_list").html(con);
|
||||||
|
|
||||||
|
|
||||||
|
$(".btn_delete_slave").click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var v = rdata.data[id];
|
||||||
|
if ('Connection_name' in v){
|
||||||
|
deleteSlave(v['Connection_name']);
|
||||||
|
} else{
|
||||||
|
deleteSlave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('.db_error').click(function(){
|
$('.db_error').click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var info = rdata.data[id];
|
||||||
|
|
||||||
|
var err_line = "";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>IO错误</td>\
|
||||||
|
<td>"+ (info['Last_IO_Error'] == '' ? '无':info['Last_IO_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>SQL错误</td>\
|
||||||
|
<td>"+(info['Last_SQL_Error'] == '' ? '无':info['Last_SQL_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>状态</td>\
|
||||||
|
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步异常信息',
|
title: '同步异常信息',
|
||||||
area: '500px',
|
area: ['600px','300px'],
|
||||||
content:"<form class='bt-form pd20 pb70'>\
|
btn:['复制错误',"取消"],
|
||||||
<div class='line'>"+v['Error']+"</div>\
|
content:"<form class='bt-form pd15'>\
|
||||||
<div class='bt-form-submit-btn'>\
|
<div class='divtable mtb10'>\
|
||||||
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
|
<div class='tablescroll'>\
|
||||||
|
<table class='table table-hover' width='100%' cellspacing='0' cellpadding='0' border='0' style='border: 0 none;'>\
|
||||||
|
<thead><tr>\
|
||||||
|
<th style='width:80px;'>类型</th>\
|
||||||
|
<th>内容</th>\
|
||||||
|
</tr></thead>\
|
||||||
|
<tbody>"+ err_line +"</tbody>\
|
||||||
|
</table>\
|
||||||
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
$('.class-copy-db-err').click(function(){
|
// $('.class-copy-db-err').click(function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
});
|
// });
|
||||||
|
},
|
||||||
|
yes:function(){
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -2320,14 +2417,12 @@ function masterOrSlaveConf(version=''){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getMasterStatus(){
|
function getMasterStatus(){
|
||||||
myPost('get_master_status', '', function(rdata){
|
myPost('get_master_status', '', function(rdata){
|
||||||
var rdata = $.parseJSON(rdata.data);
|
var rdata = $.parseJSON(rdata.data);
|
||||||
// console.log('mode:',rdata.data);
|
// console.log('mode:',rdata.data);
|
||||||
if ( typeof(rdata.status) != 'undefined' && !rdata.status && rdata.data == 'pwd'){
|
if ( typeof(rdata.status) != 'undefined' && !rdata.status && rdata.data == 'pwd'){
|
||||||
layer.msg(rdata.msg, {icon:2});
|
layer.msg(rdata.msg, {icon:2,time:2000});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2409,7 +2504,6 @@ function masterOrSlaveConf(version=''){
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
change:function(index,mode,reload){
|
change:function(index,mode,reload){
|
||||||
console.log(index,mode,reload);
|
|
||||||
myPost('set_dbrun_mode',{'mode':mode,'reload':reload},function(data){
|
myPost('set_dbrun_mode',{'mode':mode,'reload':reload},function(data){
|
||||||
layer.close(index);
|
layer.close(index);
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
@@ -2425,10 +2519,8 @@ function masterOrSlaveConf(version=''){
|
|||||||
getMasterDbList();
|
getMasterDbList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (rdata.slave_status){
|
getAsyncMasterDbList();
|
||||||
getAsyncMasterDbList();
|
getAsyncDataList()
|
||||||
getAsyncDataList()
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getMasterStatus();
|
getMasterStatus();
|
||||||
|
|||||||
@@ -71,10 +71,19 @@ Install_app()
|
|||||||
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
INSTALL_CMD=cmake
|
||||||
|
# check cmake version
|
||||||
|
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||||
|
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||||
|
mkdir -p /var/log/mariadb
|
||||||
|
touch /var/log/mariadb/mariadb.log
|
||||||
|
INSTALL_CMD=cmake3
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ ! -d $serverPath/mariadb ];then
|
if [ ! -d $serverPath/mariadb ];then
|
||||||
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
|
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||||
-DMYSQL_USER=mysql \
|
-DMYSQL_USER=mysql \
|
||||||
|
|||||||
@@ -73,8 +73,17 @@ Install_app()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
INSTALL_CMD=cmake
|
||||||
|
# check cmake version
|
||||||
|
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||||
|
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||||
|
mkdir -p /var/log/mariadb
|
||||||
|
touch /var/log/mariadb/mariadb.log
|
||||||
|
INSTALL_CMD=cmake3
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ! -d $serverPath/mariadb ];then
|
if [ ! -d $serverPath/mariadb ];then
|
||||||
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
|
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||||
-DMYSQL_USER=mysql \
|
-DMYSQL_USER=mysql \
|
||||||
|
|||||||
@@ -72,9 +72,17 @@ Install_app()
|
|||||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
INSTALL_CMD=cmake
|
||||||
|
# check cmake version
|
||||||
|
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||||
|
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||||
|
mkdir -p /var/log/mariadb
|
||||||
|
touch /var/log/mariadb/mariadb.log
|
||||||
|
INSTALL_CMD=cmake3
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ! -d $serverPath/mariadb ];then
|
if [ ! -d $serverPath/mariadb ];then
|
||||||
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
|
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||||
-DMYSQL_USER=mysql \
|
-DMYSQL_USER=mysql \
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ if mw.isAppleSystem():
|
|||||||
app_debug = True
|
app_debug = True
|
||||||
|
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
def getPluginName():
|
||||||
return 'memcached'
|
return 'memcached'
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ port = 33206
|
|||||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
language={$SERVER_APP_PATH}/bin/usr/share/mysql/english
|
language={$SERVER_APP_PATH}/bin/usr/share/mysql/english
|
||||||
|
|
||||||
@@ -45,7 +48,6 @@ skip-ssl
|
|||||||
|
|
||||||
log-bin=mysql-bin
|
log-bin=mysql-bin
|
||||||
binlog_format=mixed
|
binlog_format=mixed
|
||||||
server-id = 1
|
|
||||||
slow_query_log=1
|
slow_query_log=1
|
||||||
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
||||||
long_query_time=3
|
long_query_time=3
|
||||||
@@ -71,6 +73,9 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ mysqlx_port = 33260
|
|||||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
|
|
||||||
key_buffer_size = 8M
|
key_buffer_size = 8M
|
||||||
@@ -43,7 +46,6 @@ max_allowed_packet = 128M
|
|||||||
|
|
||||||
log-bin=mysql-bin
|
log-bin=mysql-bin
|
||||||
binlog_format=mixed
|
binlog_format=mixed
|
||||||
server-id = 1
|
|
||||||
slow_query_log=1
|
slow_query_log=1
|
||||||
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
||||||
long_query_time=3
|
long_query_time=3
|
||||||
@@ -68,6 +70,9 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<p onclick="dbList()">管理列表</p>
|
<p onclick="dbList()">管理列表</p>
|
||||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bt-w-con pd15">
|
<div class="bt-w-con pd15" style="height:555px;overflow: auto;">
|
||||||
<div class="soft-man-con"></div>
|
<div class="soft-man-con"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+214
-140
@@ -28,6 +28,10 @@ def getPluginDir():
|
|||||||
return mw.getPluginDir() + '/' + getPluginName()
|
return mw.getPluginDir() + '/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
|
def getSPluginDir():
|
||||||
|
return '/www/server/mdserver-web/plugins/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
def getServerDir():
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
return mw.getServerDir() + '/' + getPluginName()
|
||||||
|
|
||||||
@@ -116,6 +120,10 @@ def contentReplace(content):
|
|||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
content = content.replace('{$SERVER_PATH}', service_path)
|
||||||
content = content.replace('{$SERVER_APP_PATH}',
|
content = content.replace('{$SERVER_APP_PATH}',
|
||||||
service_path + '/' + getPluginName())
|
service_path + '/' + getPluginName())
|
||||||
|
|
||||||
|
server_id = int(time.time())
|
||||||
|
content = content.replace('{$SERVER_ID}', str(server_id))
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
@@ -161,6 +169,10 @@ def pMysqlDb():
|
|||||||
|
|
||||||
def initDreplace(version=''):
|
def initDreplace(version=''):
|
||||||
|
|
||||||
|
t = getServerDir()
|
||||||
|
if not os.path.exists(t):
|
||||||
|
return
|
||||||
|
|
||||||
conf_dir = getServerDir() + '/etc'
|
conf_dir = getServerDir() + '/etc'
|
||||||
mode_dir = conf_dir + '/mode'
|
mode_dir = conf_dir + '/mode'
|
||||||
|
|
||||||
@@ -654,15 +666,15 @@ def isSqlError(mysqlMsg):
|
|||||||
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||||
if "using password:" in mysqlMsg:
|
if "using password:" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
||||||
if "1045" in mysqlMsg:
|
if "1045," in mysqlMsg:
|
||||||
return mw.returnJson(False, '连接错误!')
|
return mw.returnJson(False, '连接错误!')
|
||||||
if "SQL syntax" in mysqlMsg:
|
if "SQL syntax" in mysqlMsg:
|
||||||
return mw.returnJson(False, 'SQL语法错误!')
|
return mw.returnJson(False, 'SQL语法错误!')
|
||||||
if "Connection refused" in mysqlMsg:
|
if "Connection refused" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||||
if "1133" in mysqlMsg:
|
if "1133," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库用户不存在!')
|
return mw.returnJson(False, '数据库用户不存在!')
|
||||||
if "1007" in mysqlMsg:
|
if "1007," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库已经存在!')
|
return mw.returnJson(False, '数据库已经存在!')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1885,27 +1897,34 @@ def getMasterRepSlaveUserCmd(version):
|
|||||||
|
|
||||||
mode = recognizeDbMode()
|
mode = recognizeDbMode()
|
||||||
|
|
||||||
|
sid = getDbServerId()
|
||||||
|
channel_name = ""
|
||||||
|
if sid != '':
|
||||||
|
channel_name = " for channel 'r{}';".format(sid)
|
||||||
|
|
||||||
if mode == "gtid":
|
if mode == "gtid":
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + "', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
if version == '8.0':
|
if version == '8.0':
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + \
|
||||||
|
"', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
else:
|
else:
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"])
|
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
if version == "8.0":
|
if version == "8.0":
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',SOURCE_LOG_POS=" + str(mstatus[0]["Position"])
|
"',SOURCE_LOG_POS=" + \
|
||||||
|
str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
data['cmd'] = sql
|
data['cmd'] = sql
|
||||||
@@ -2217,7 +2236,7 @@ def getSlaveSyncCmd(version=''):
|
|||||||
|
|
||||||
root = mw.getRunDir()
|
root = mw.getRunDir()
|
||||||
cmd = 'cd ' + root + ' && python3 ' + root + \
|
cmd = 'cd ' + root + ' && python3 ' + root + \
|
||||||
'/plugins/mysql/index.py do_full_sync {"db":"all"}'
|
'/plugins/mysql/index.py do_full_sync {"db":"all","sign":""}'
|
||||||
return mw.returnJson(True, 'ok', cmd)
|
return mw.returnJson(True, 'ok', cmd)
|
||||||
|
|
||||||
|
|
||||||
@@ -2233,100 +2252,151 @@ def initSlaveStatus(version=''):
|
|||||||
return initSlaveStatusSyncUser(version)
|
return initSlaveStatusSyncUser(version)
|
||||||
|
|
||||||
|
|
||||||
|
def parseSlaveSyncCmd(cmd):
|
||||||
|
a = {}
|
||||||
|
if cmd.lower().find('for') > 0:
|
||||||
|
cmd_tmp = cmd.split('for')
|
||||||
|
cmd = cmd_tmp[0].strip()
|
||||||
|
|
||||||
|
pattern_c = r"channel \'(.*)\';"
|
||||||
|
match_val = re.match(pattern_c, cmd_tmp[1].strip(), re.I)
|
||||||
|
if match_val:
|
||||||
|
m_groups = match_val.groups()
|
||||||
|
a['channel'] = m_groups[0]
|
||||||
|
vlist = cmd.split(',')
|
||||||
|
for i in vlist:
|
||||||
|
tmp = i.strip()
|
||||||
|
tmp_a = tmp.split(" ")
|
||||||
|
real_tmp = tmp_a[len(tmp_a) - 1]
|
||||||
|
kv = real_tmp.split("=")
|
||||||
|
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSyncUser(version=''):
|
def initSlaveStatusSyncUser(version=''):
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
slave_data = conn.field('ip,port,user,pass,mode,cmd').select()
|
||||||
if len(data) < 1:
|
if len(slave_data) < 1:
|
||||||
return mw.returnJson(False, '需要先添加同步用户配置!')
|
return mw.returnJson(False, '需要先添加同步用户配置!')
|
||||||
|
|
||||||
# print(data)
|
# print(data)
|
||||||
db = pMysqlDb()
|
pdb = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
if len(slave_data) == 1:
|
||||||
if len(dlist) > 0:
|
dlist = pdb.query('show slave status')
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
if len(dlist) > 0:
|
||||||
|
return mw.returnJson(False, '已经初始化好了zz...')
|
||||||
u = data
|
|
||||||
|
|
||||||
mode_name = 'classic'
|
|
||||||
if u['mode'] == '1':
|
|
||||||
mode_name = 'gtid'
|
|
||||||
|
|
||||||
|
msg = ''
|
||||||
local_mode = recognizeDbMode()
|
local_mode = recognizeDbMode()
|
||||||
if local_mode != mode_name:
|
for x in range(len(slave_data)):
|
||||||
return mw.returnJson(False, '同步模式不一致!')
|
slave_t = slave_data[x]
|
||||||
|
mode_name = 'classic'
|
||||||
|
base_t = 'IP:' + slave_t['ip'] + ",PORT:" + \
|
||||||
|
slave_t['port'] + ",USER:" + slave_t['user']
|
||||||
|
|
||||||
t = db.query(u['cmd'])
|
if slave_t['mode'] == '1':
|
||||||
# print(t)
|
mode_name = 'gtid'
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
|
||||||
u['user'], u['pass']))
|
if local_mode != mode_name:
|
||||||
return mw.returnJson(True, '初始化成功!')
|
msg += base_t + '->同步模式不一致'
|
||||||
|
continue
|
||||||
|
|
||||||
|
cmd_sql = slave_t['cmd']
|
||||||
|
if cmd_sql == '':
|
||||||
|
msg += base_t + '->同步命令不能为空'
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
pinfo = parseSlaveSyncCmd(cmd_sql)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
|
||||||
|
t = pdb.query(cmd_sql)
|
||||||
|
isError = isSqlError(t)
|
||||||
|
if isError:
|
||||||
|
return isError
|
||||||
|
|
||||||
|
# pdb.query("start slave user='{}' password='{}';".format(
|
||||||
|
# u['user'], u['pass']))
|
||||||
|
|
||||||
|
pdb.query("start slave")
|
||||||
|
pdb.query("start all slaves")
|
||||||
|
|
||||||
|
if msg == '':
|
||||||
|
msg = '初始化成功!'
|
||||||
|
return mw.returnJson(True, msg)
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSSH(version=''):
|
def initSlaveStatusSSH(version=''):
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
if len(dlist) > 0:
|
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
|
||||||
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
conn = pSqliteDb('slave_id_rsa')
|
||||||
data = conn.field('ip,port,id_rsa').find()
|
ssh_list = conn.field('ip,port,id_rsa,db_user').select()
|
||||||
|
|
||||||
if len(data) < 1:
|
if len(ssh_list) < 1:
|
||||||
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
|
local_mode = recognizeDbMode()
|
||||||
ip = data['ip']
|
|
||||||
master_port = data['port']
|
|
||||||
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
paramiko.util.log_to_file('paramiko.log')
|
paramiko.util.log_to_file('paramiko.log')
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
|
|
||||||
try:
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
for data in ssh_list:
|
||||||
|
ip = data['ip']
|
||||||
|
SSH_PRIVATE_KEY = "/tmp/t_ssh_" + ip + ".txt"
|
||||||
|
master_port = data['port']
|
||||||
|
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
||||||
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
||||||
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
try:
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
||||||
ssh.connect(hostname=ip, port=int(master_port),
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
username='root', pkey=key)
|
ssh.connect(hostname=ip, port=int(master_port),
|
||||||
|
username='root', pkey=key)
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}'
|
db_user = data['db_user']
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \
|
||||||
result = stdout.read()
|
getSPluginDir() + \
|
||||||
result = result.decode('utf-8')
|
'/index.py get_master_rep_slave_user_cmd {"username":"' + \
|
||||||
cmd_data = json.loads(result)
|
db_user + '","db":""}'
|
||||||
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
|
result = stdout.read()
|
||||||
|
result = result.decode('utf-8')
|
||||||
|
if result.strip() == "":
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:获取同步命令失败!')
|
||||||
|
|
||||||
if not cmd_data['status']:
|
cmd_data = json.loads(result)
|
||||||
return mw.returnJson(False, '[主]:' + cmd_data['msg'])
|
if not cmd_data['status']:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg'])
|
||||||
|
|
||||||
local_mode = recognizeDbMode()
|
if local_mode != cmd_data['data']['mode']:
|
||||||
if local_mode != cmd_data['data']['mode']:
|
return mw.returnJson(False, '[主][' + ip + ']:【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
||||||
return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
|
||||||
|
|
||||||
u = cmd_data['data']['info']
|
u = cmd_data['data']['info']
|
||||||
ps = u['username'] + "|" + u['password']
|
|
||||||
conn.where('ip=?', (ip,)).setField('ps', ps)
|
|
||||||
db.query('stop slave')
|
|
||||||
|
|
||||||
# 保证同步IP一致
|
ps = u['username'] + "|" + u['password']
|
||||||
cmd = cmd_data['data']['cmd']
|
print(ps)
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
conn.where('ip=?', (ip,)).setField('ps', ps)
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*)'",
|
db.query('stop slave')
|
||||||
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
# 保证同步IP一致
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*)'",
|
cmd = cmd_data['data']['cmd']
|
||||||
"MASTER_HOST='" + ip + "'", cmd, 1)
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
db.query(cmd)
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
u['username'], u['password']))
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e))
|
|
||||||
|
|
||||||
ssh.close()
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
time.sleep(1)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
db.query(cmd)
|
||||||
|
ssh.close()
|
||||||
|
if os.path.exists(SSH_PRIVATE_KEY):
|
||||||
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:SSH认证配置连接失败!' + str(e))
|
||||||
|
db.query('start slave')
|
||||||
return mw.returnJson(True, '初始化成功!')
|
return mw.returnJson(True, '初始化成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2336,60 +2406,37 @@ def setSlaveStatus(version=''):
|
|||||||
return mw.returnJson(False, '需要先设置同步配置')
|
return mw.returnJson(False, '需要先设置同步配置')
|
||||||
|
|
||||||
mode = mw.readFile(mode_file)
|
mode = mw.readFile(mode_file)
|
||||||
if mode == 'ssh':
|
pdb = pMysqlDb()
|
||||||
return setSlaveStatusSSH(version)
|
dlist = pdb.query('show slave status')
|
||||||
if mode == 'sync-user':
|
|
||||||
return setSlaveStatusSyncUser(version)
|
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSyncUser(version=''):
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
if len(dlist) == 0:
|
||||||
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
for v in dlist:
|
||||||
db.query('stop slave')
|
connection_name = ''
|
||||||
else:
|
cmd = "slave"
|
||||||
ip = dlist[0]['Master_Host']
|
if 'Channel_Name' in v:
|
||||||
conn = pSqliteDb('slave_sync_user')
|
ch_name = v['Channel_Name']
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
cmd = "slave for channel '{}'".format(ch_name)
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
user = data['user']
|
|
||||||
apass = data['pass']
|
|
||||||
|
|
||||||
db.query("start slave")
|
if (v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes'):
|
||||||
# db.query("start slave user='{}' password='{}';".format(user, apass))
|
pdb.query("stop {}".format(cmd))
|
||||||
|
else:
|
||||||
return mw.returnJson(True, '设置成功!')
|
pdb.query("start {}".format(cmd))
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSSH(version=''):
|
|
||||||
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
|
||||||
return mw.returnJson(False, '需要手动添加主服务命令或者执行[初始化]!')
|
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
|
||||||
db.query('stop slave')
|
|
||||||
else:
|
|
||||||
ip = dlist[0]['Master_Host']
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
|
||||||
data = conn.field('ip,ps').where("ip=?", (ip,)).find()
|
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
u = data['ps'].split("|")
|
|
||||||
db.query("start slave user='{}' password='{}';".format(u[0], u[1]))
|
|
||||||
|
|
||||||
return mw.returnJson(True, '设置成功!')
|
return mw.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
|
||||||
def deleteSlave(version=''):
|
def deleteSlave(version=''):
|
||||||
|
args = getArgs()
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('stop slave')
|
if 'sign' in args:
|
||||||
dlist = db.query('reset slave all')
|
sign = args['sign']
|
||||||
|
db.query("stop slave for channel '{}'".format(sign))
|
||||||
|
db.query("reset slave all for channel '{}'".format(sign))
|
||||||
|
else:
|
||||||
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
return mw.returnJson(True, '删除成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2425,11 +2472,13 @@ def dumpMysqlData(version=''):
|
|||||||
|
|
||||||
############### --- 重要 同步---- ###########
|
############### --- 重要 同步---- ###########
|
||||||
|
|
||||||
|
def asyncTmpfile():
|
||||||
|
path = '/tmp/mysql_apt_async_status.txt'
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def writeDbSyncStatus(data):
|
def writeDbSyncStatus(data):
|
||||||
path = '/tmp/db_async_status.txt'
|
path = asyncTmpfile()
|
||||||
# status_data['code'] = 1
|
|
||||||
# status_data['msg'] = '主服务器备份完成...'
|
|
||||||
# status_data['progress'] = 30
|
|
||||||
mw.writeFile(path, json.dumps(data))
|
mw.writeFile(path, json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
@@ -2447,16 +2496,22 @@ def doFullSync(version=''):
|
|||||||
|
|
||||||
def doFullSyncUser(version=''):
|
def doFullSyncUser(version=''):
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
sync_db = args['db']
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
if sync_sign != '':
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
||||||
|
|
||||||
user = data['user']
|
user = data['user']
|
||||||
apass = data['pass']
|
apass = data['pass']
|
||||||
port = data['port']
|
port = data['port']
|
||||||
@@ -2473,16 +2528,17 @@ def doFullSyncUser(version=''):
|
|||||||
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
|
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
|
||||||
|
|
||||||
if not os.path.exists(bak_file):
|
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" + \
|
dump_sql_data = getServerDir() + "/bin/usr/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
|
||||||
port + " -u" + user + " -p" + apass + \
|
port + " -u" + user + " -p\"" + apass + \
|
||||||
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
|
"\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
|
||||||
|
# print(dump_sql_data)
|
||||||
mw.execShell(dump_sql_data)
|
mw.execShell(dump_sql_data)
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
||||||
if os.path.exists(bak_file):
|
if os.path.exists(bak_file):
|
||||||
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||||
sock = getSocketFile()
|
sock = getSocketFile()
|
||||||
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
|
my_import_cmd = getServerDir() + '/bin/usr/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
|
||||||
' ' + sync_db + ' < ' + bak_file
|
' ' + sync_db + ' < ' + bak_file
|
||||||
mw.execShell(my_import_cmd)
|
mw.execShell(my_import_cmd)
|
||||||
|
|
||||||
@@ -2492,21 +2548,30 @@ def doFullSyncUser(version=''):
|
|||||||
db.query("start slave")
|
db.query("start slave")
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
os.system("rm -rf " + bak_file)
|
|
||||||
|
if os.path.exists(bak_file):
|
||||||
|
os.system("rm -rf " + bak_file)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def doFullSyncSSH(version=''):
|
def doFullSyncSSH(version=''):
|
||||||
|
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
||||||
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
if sync_sign != '':
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
||||||
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
||||||
@@ -2548,7 +2613,8 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
||||||
|
|
||||||
dbname = args['db']
|
dbname = args['db']
|
||||||
cmd = "cd /www/server/mdserver-web && python3 plugins/mysql/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
cmd = "cd /www/server/mdserver-web && source bin/activate && python3 " + \
|
||||||
|
getSPluginDir() + "/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
||||||
print(cmd)
|
print(cmd)
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
@@ -2571,7 +2637,10 @@ def doFullSyncSSH(version=''):
|
|||||||
if copy_status == None:
|
if copy_status == None:
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \
|
||||||
|
getSPluginDir() + \
|
||||||
|
'/index.py get_master_rep_slave_user_cmd {"username":"' + \
|
||||||
|
db_user + '","db":""}'
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
result = result.decode('utf-8')
|
result = result.decode('utf-8')
|
||||||
@@ -2583,10 +2652,12 @@ def doFullSyncSSH(version=''):
|
|||||||
cmd = cmd_data['data']['cmd']
|
cmd = cmd_data['data']['cmd']
|
||||||
# 保证同步IP一致
|
# 保证同步IP一致
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
db.query(cmd)
|
db.query(cmd)
|
||||||
uinfo = cmd_data['data']['info']
|
uinfo = cmd_data['data']['info']
|
||||||
@@ -2598,8 +2669,10 @@ def doFullSyncSSH(version=''):
|
|||||||
root_dir = getServerDir()
|
root_dir = getServerDir()
|
||||||
msock = root_dir + "/mysql.sock"
|
msock = root_dir + "/mysql.sock"
|
||||||
mw.execShell("cd /tmp && gzip -d dump.sql.gz")
|
mw.execShell("cd /tmp && gzip -d dump.sql.gz")
|
||||||
cmd = root_dir + "/bin/mysql -S " + msock + \
|
cmd = root_dir + "/bin/usr/bin/mysql -S " + msock + \
|
||||||
" -uroot -p" + pwd + " < /tmp/dump.sql"
|
" -uroot -p" + pwd + " < /tmp/dump.sql"
|
||||||
|
|
||||||
|
print(cmd)
|
||||||
import_data = mw.execShell(cmd)
|
import_data = mw.execShell(cmd)
|
||||||
if import_data[0] == '':
|
if import_data[0] == '':
|
||||||
print(import_data[1])
|
print(import_data[1])
|
||||||
@@ -2609,8 +2682,9 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
# "start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password'])
|
||||||
uinfo['username'], uinfo['password']))
|
|
||||||
|
db.query("start slave")
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
|
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
@@ -2624,12 +2698,12 @@ def fullSync(version=''):
|
|||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
status_file = '/tmp/db_async_status.txt'
|
status_file = asyncTmpfile()
|
||||||
if args['begin'] == '1':
|
if args['begin'] == '1':
|
||||||
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + getPluginDir() + \
|
||||||
getPluginDir() + \
|
'/index.py do_full_sync {"db":"' + \
|
||||||
'/index.py do_full_sync {"db":"' + args['db'] + '"} &'
|
args['db'] + '","sign":"' + sign + '"} &'
|
||||||
print(cmd)
|
# print(cmd)
|
||||||
mw.execShell(cmd)
|
mw.execShell(cmd)
|
||||||
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,11 @@ fi
|
|||||||
sh -x $curPath/versions/$2/install.sh $1
|
sh -x $curPath/versions/$2/install.sh $1
|
||||||
|
|
||||||
if [ "${action}" == "install" ];then
|
if [ "${action}" == "install" ];then
|
||||||
# #初始化
|
#初始化
|
||||||
|
|
||||||
|
if [ "$?" != "0" ];then
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py start ${type}
|
cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py start ${type}
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py initd_install ${type}
|
cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py initd_install ${type}
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -162,34 +162,6 @@ function myPort(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//数据库存储信置
|
|
||||||
function changeMySQLDataPath(act) {
|
|
||||||
if (act != undefined) {
|
|
||||||
layer.confirm(lan.soft.mysql_to_msg, { closeBtn: 2, icon: 3 }, function() {
|
|
||||||
var datadir = $("#datadir").val();
|
|
||||||
var data = 'datadir=' + datadir;
|
|
||||||
var loadT = layer.msg(lan.soft.mysql_to_msg1, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
|
||||||
$.post('/database?action=SetDataDir', data, function(rdata) {
|
|
||||||
layer.close(loadT)
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/database?action=GetMySQLInfo', '', function(rdata) {
|
|
||||||
var LimitCon = '<p class="conf_p">\
|
|
||||||
<input id="datadir" class="phpUploadLimit bt-input-text mr5" style="width:350px;" type="text" value="' + rdata.datadir + '" name="datadir">\
|
|
||||||
<span onclick="ChangePath(\'datadir\')" class="glyphicon glyphicon-folder-open cursor mr20" style="width:auto"></span><button class="btn btn-success btn-sm" onclick="changeMySQLDataPath(1)">' + lan.soft.mysql_to + '</button>\
|
|
||||||
</p>';
|
|
||||||
$(".soft-man-con").html(LimitCon);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//数据库配置状态
|
//数据库配置状态
|
||||||
function myPerfOpt() {
|
function myPerfOpt() {
|
||||||
//获取MySQL配置
|
//获取MySQL配置
|
||||||
@@ -1691,12 +1663,12 @@ function getMasterRepSlaveListPage(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteSlave(){
|
function deleteSlave(sign){
|
||||||
myPost('delete_slave', {}, function(data){
|
myPost('delete_slave', {sign:sign}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
showMsg(rdata['msg'], function(){
|
showMsg(rdata['msg'], function(){
|
||||||
masterOrSlaveConf();
|
masterOrSlaveConf();
|
||||||
},{},3000);
|
},{icon:rdata.status?1:2,time:3000},3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1704,28 +1676,73 @@ function deleteSlave(){
|
|||||||
function getFullSyncStatus(db){
|
function getFullSyncStatus(db){
|
||||||
var timeId = null;
|
var timeId = null;
|
||||||
|
|
||||||
var btn = '<div class="table_toolbar" style="left:0px;"><span data-status="init" class="sync btn btn-default btn-sm" id="begin_full_sync" title="">开始</span></div>';
|
myPost('get_slave_list', {page:1,page_size:100}, function(data){
|
||||||
var loadOpen = layer.open({
|
var rdata = $.parseJSON(data.data);
|
||||||
type: 1,
|
var rsource = rdata.data;
|
||||||
title: '全量同步['+db+']',
|
|
||||||
area: '500px',
|
if (db == 'ALL' && rsource.length>1){
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
layer.msg("多主不支持该模式!",{icon:2});
|
||||||
<div class='divtable mtb10'>\
|
return;
|
||||||
<span id='full_msg'></span>\
|
|
||||||
<div class='progress'>\
|
|
||||||
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
"+btn+"\
|
|
||||||
</div>",
|
|
||||||
cancel: function(){
|
|
||||||
clearInterval(timeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dataSource = '';
|
||||||
|
if (rsource.length>1){
|
||||||
|
var sourceList = '';
|
||||||
|
for (var i = 0; i < rsource.length; i++) {
|
||||||
|
if ('Channel_Name' in rsource[i]){
|
||||||
|
sourceList += '<option val="'+rsource[i]['Master_Host']+'">'+rsource[i]['Master_Host']+'</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource = "<p class='line' style='text-align:center;'>\
|
||||||
|
<span>同步数据源:</span>\
|
||||||
|
<select class='bt-input-text' name='data_source' style='width:200px;'>" + sourceList + "</select>\
|
||||||
|
</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '全量同步['+db+']',
|
||||||
|
area: '500px',
|
||||||
|
content:"<div class='bt-form pd15'>\
|
||||||
|
<div class='divtable mtb10'>\
|
||||||
|
"+dataSource+"\
|
||||||
|
<span id='full_msg'></span>\
|
||||||
|
<div class='progress'>\
|
||||||
|
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class='table_toolbar' style='left:0px;'>\
|
||||||
|
<span data-status='init' class='sync btn btn-default btn-sm' id='begin_full_sync'>开始</span>\
|
||||||
|
</div>\
|
||||||
|
</div>",
|
||||||
|
cancel: function(){
|
||||||
|
clearInterval(timeId);
|
||||||
|
},
|
||||||
|
success:function(){
|
||||||
|
$('#begin_full_sync').click(function(){
|
||||||
|
var val = $(this).data('status');
|
||||||
|
var sign = '';
|
||||||
|
if (dataSource !=''){
|
||||||
|
sign = $('select[name="data_source"]').val();
|
||||||
|
}
|
||||||
|
if (val == 'init'){
|
||||||
|
fullSync(db, sign, 1);
|
||||||
|
timeId = setInterval(function(){
|
||||||
|
fullSync(db,sign,0);
|
||||||
|
}, 1000);
|
||||||
|
$(this).data('status','starting');
|
||||||
|
} else {
|
||||||
|
layer.msg("正在同步中..",{icon:0});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function fullSync(db,begin){
|
function fullSync(db,sign,begin){
|
||||||
|
|
||||||
myPostN('full_sync', {db:db,begin:begin}, function(data){
|
myPostN('full_sync', {db:db,sign:sign,begin:begin}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
$('#full_msg').text(rdata['msg']);
|
$('#full_msg').text(rdata['msg']);
|
||||||
$('.progress-bar').css('width',rdata['progress']+'%');
|
$('.progress-bar').css('width',rdata['progress']+'%');
|
||||||
@@ -1734,23 +1751,10 @@ function getFullSyncStatus(db){
|
|||||||
if (rdata['code']==6 ||rdata['code']<0){
|
if (rdata['code']==6 ||rdata['code']<0){
|
||||||
layer.msg(rdata['msg']);
|
layer.msg(rdata['msg']);
|
||||||
clearInterval(timeId);
|
clearInterval(timeId);
|
||||||
$("#begin_full_sync").attr('data-status','init');
|
$("#begin_full_sync").data('data','init');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#begin_full_sync').click(function(){
|
|
||||||
var val = $(this).attr('data-status');
|
|
||||||
if (val == 'init'){
|
|
||||||
fullSync(db,1);
|
|
||||||
timeId = setInterval(function(){
|
|
||||||
fullSync(db,0);
|
|
||||||
}, 1000);
|
|
||||||
$(this).attr('data-status','starting');
|
|
||||||
} else {
|
|
||||||
layer.msg("正在同步中..");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSlaveSSH(ip=''){
|
function addSlaveSSH(ip=''){
|
||||||
@@ -1920,18 +1924,29 @@ function addSlaveSyncUser(ip=''){
|
|||||||
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
||||||
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
||||||
<div class='line'>\
|
<div class='line'>\
|
||||||
<span class='tname'>CMD[最好填好]</span>\
|
<span class='tname'>CMD[必须填写]</span>\
|
||||||
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<input type='hidden' name='mode' value='"+mode+"' />\
|
<input type='hidden' name='mode' value='"+mode+"' />\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
$('textarea[name="cmd"]').html(cmd);
|
$('textarea[name="cmd"]').html(cmd);
|
||||||
|
|
||||||
$('textarea[name="cmd"]').change(function(){
|
$('textarea[name="cmd"]').change(function(){
|
||||||
var val = $(this).val();
|
var val = $(this).val();
|
||||||
var vlist = val.split(',');
|
|
||||||
var a = {};
|
var a = {};
|
||||||
|
if (val.toLowerCase().indexOf('for')>0){
|
||||||
|
cmd_tmp = val.split('for');
|
||||||
|
val = cmd_tmp[0].trim();
|
||||||
|
|
||||||
|
const channel_str = cmd_tmp[1].trim();
|
||||||
|
const ch_reg = /channel \'(.*)\';/;
|
||||||
|
var match_val = channel_str.match(ch_reg);
|
||||||
|
if (match_val.length>1){
|
||||||
|
a['channel'] = match_val[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlist = val.split(',');
|
||||||
for (var i in vlist) {
|
for (var i in vlist) {
|
||||||
var tmp = toTrim(vlist[i]);
|
var tmp = toTrim(vlist[i]);
|
||||||
var tmp_a = tmp.split(" ");
|
var tmp_a = tmp.split(" ");
|
||||||
@@ -2098,7 +2113,7 @@ function getSlaveUserList(){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步账户列表',
|
title: '同步账户列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2122,7 +2137,7 @@ function getSlaveSSHList(page=1){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: 'SSH列表',
|
title: 'SSH列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2230,10 +2245,16 @@ function masterOrSlaveConf(version=''){
|
|||||||
myPost('get_slave_list', _data, function(data){
|
myPost('get_slave_list', _data, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
var list = '';
|
var list = '';
|
||||||
|
|
||||||
|
var isHasSign = false;
|
||||||
for(i in rdata.data){
|
for(i in rdata.data){
|
||||||
|
|
||||||
var v = rdata.data[i];
|
var v = rdata.data[i];
|
||||||
var status = "<a class='btlink db_error'>异常</>";
|
if ('Channel_Name' in v){
|
||||||
|
isHasSign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = "<a data-id="+i+" class='btlink db_error'>异常</>";
|
||||||
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
||||||
status = "正常";
|
status = "正常";
|
||||||
}
|
}
|
||||||
@@ -2245,13 +2266,23 @@ function masterOrSlaveConf(version=''){
|
|||||||
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
||||||
|
|
||||||
|
if (isHasSign){
|
||||||
|
list += '<td>' + v['Channel_Name'] +'</td>';
|
||||||
|
}
|
||||||
|
|
||||||
list += '<td>' + status +'</td>';
|
list += '<td>' + status +'</td>';
|
||||||
list += '<td style="text-align:right">' +
|
list += '<td style="text-align:right">' +
|
||||||
'<a href="javascript:;" class="btlink" onclick="deleteSlave()" title="删除">删除</a>' +
|
'<a data-id="'+i+'" href="javascript:;" class="btlink btn_delete_slave" title="删除">删除</a>' +
|
||||||
'</td>';
|
'</td>';
|
||||||
list += '</tr>';
|
list += '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var signThead_th = '';
|
||||||
|
if (isHasSign){
|
||||||
|
var signThead_th = '<th>标识</th>';
|
||||||
|
}
|
||||||
|
|
||||||
var con = '<div class="divtable mtb10">\
|
var con = '<div class="divtable mtb10">\
|
||||||
<div class="tablescroll">\
|
<div class="tablescroll">\
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||||
@@ -2262,6 +2293,7 @@ function masterOrSlaveConf(version=''){
|
|||||||
<th>日志</th>\
|
<th>日志</th>\
|
||||||
<th>IO</th>\
|
<th>IO</th>\
|
||||||
<th>SQL</th>\
|
<th>SQL</th>\
|
||||||
|
'+signThead_th+'\
|
||||||
<th>状态</th>\
|
<th>状态</th>\
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
<th style="text-align:right;">操作</th></tr></thead>\
|
||||||
<tbody>\
|
<tbody>\
|
||||||
@@ -2276,22 +2308,74 @@ function masterOrSlaveConf(version=''){
|
|||||||
// </div>
|
// </div>
|
||||||
$(".table_slave_status_list").html(con);
|
$(".table_slave_status_list").html(con);
|
||||||
|
|
||||||
$('.db_error').click(function(){
|
$(".btn_delete_slave").click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var v = rdata.data[id];
|
||||||
|
if ('Channel_Name' in v){
|
||||||
|
deleteSlave(v['Channel_Name']);
|
||||||
|
} else{
|
||||||
|
deleteSlave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.db_error').click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var info = rdata.data[id];
|
||||||
|
|
||||||
|
var err_line = "";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>IO错误</td>\
|
||||||
|
<td>"+ (info['Last_IO_Error'] == '' ? '无':info['Last_IO_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>SQL错误</td>\
|
||||||
|
<td>"+(info['Last_SQL_Error'] == '' ? '无':info['Last_SQL_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>状态</td>\
|
||||||
|
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步异常信息',
|
title: '同步异常信息',
|
||||||
area: '500px',
|
area: ['600px','300px'],
|
||||||
content:"<form class='bt-form pd20 pb70'>\
|
btn:['复制错误',"取消"],
|
||||||
<div class='line'>"+v['Error']+"</div>\
|
content:"<form class='bt-form pd15'>\
|
||||||
<div class='bt-form-submit-btn'>\
|
<div class='divtable mtb10'>\
|
||||||
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
|
<div class='tablescroll'>\
|
||||||
|
<table class='table table-hover' width='100%' cellspacing='0' cellpadding='0' border='0' style='border: 0 none;'>\
|
||||||
|
<thead><tr>\
|
||||||
|
<th style='width:80px;'>类型</th>\
|
||||||
|
<th>内容</th>\
|
||||||
|
</tr></thead>\
|
||||||
|
<tbody>"+ err_line +"</tbody>\
|
||||||
|
</table>\
|
||||||
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
$('.class-copy-db-err').click(function(){
|
// $('.class-copy-db-err').click(function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
});
|
// });
|
||||||
|
},
|
||||||
|
yes:function(){
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,22 @@ if [ "$OSNAME" == "ubuntu" ];then
|
|||||||
VERSION_ID="18.04"
|
VERSION_ID="18.04"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_amd64
|
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 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_${ARCH}
|
||||||
|
|
||||||
APT_INSTALL()
|
APT_INSTALL()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,8 +22,25 @@ VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -
|
|||||||
|
|
||||||
# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh install 8.0
|
# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh install 8.0
|
||||||
|
|
||||||
|
|
||||||
|
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.0.30
|
MYSQL_VER=8.0.30
|
||||||
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_amd64
|
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_${ARCH}
|
||||||
|
|
||||||
|
|
||||||
# /lib/systemd/system/mysql.service
|
# /lib/systemd/system/mysql.service
|
||||||
@@ -81,7 +98,6 @@ Install_mysql()
|
|||||||
useradd -g mysql mysql
|
useradd -g mysql mysql
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
isApt=`which apt`
|
isApt=`which apt`
|
||||||
if [ "$isApt" != "" ];then
|
if [ "$isApt" != "" ];then
|
||||||
APT_INSTALL
|
APT_INSTALL
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ port = 33206
|
|||||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
language={$SERVER_APP_PATH}/bin/usr/share/mysql/english
|
language={$SERVER_APP_PATH}/bin/usr/share/mysql/english
|
||||||
|
|
||||||
@@ -46,7 +49,6 @@ skip-ssl
|
|||||||
|
|
||||||
log-bin=mysql-bin
|
log-bin=mysql-bin
|
||||||
binlog_format=mixed
|
binlog_format=mixed
|
||||||
server-id = 1
|
|
||||||
slow_query_log=1
|
slow_query_log=1
|
||||||
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
||||||
long_query_time=3
|
long_query_time=3
|
||||||
@@ -72,6 +74,9 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ mysqlx_port = 33260
|
|||||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
|
|
||||||
key_buffer_size = 8M
|
key_buffer_size = 8M
|
||||||
@@ -43,7 +46,6 @@ max_allowed_packet = 128M
|
|||||||
|
|
||||||
log-bin=mysql-bin
|
log-bin=mysql-bin
|
||||||
binlog_format=mixed
|
binlog_format=mixed
|
||||||
server-id = 1
|
|
||||||
slow_query_log=1
|
slow_query_log=1
|
||||||
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
||||||
long_query_time=3
|
long_query_time=3
|
||||||
@@ -68,6 +70,9 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<p onclick="dbList()">管理列表</p>
|
<p onclick="dbList()">管理列表</p>
|
||||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bt-w-con pd15">
|
<div class="bt-w-con pd15" style="height:555px;overflow: auto;">
|
||||||
<div class="soft-man-con"></div>
|
<div class="soft-man-con"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+219
-152
@@ -36,6 +36,10 @@ def getPluginDir():
|
|||||||
return mw.getPluginDir() + '/' + getPluginName()
|
return mw.getPluginDir() + '/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
|
def getSPluginDir():
|
||||||
|
return '/www/server/mdserver-web/plugins/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
def getServerDir():
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
return mw.getServerDir() + '/' + getPluginName()
|
||||||
|
|
||||||
@@ -101,6 +105,14 @@ def getDbPort():
|
|||||||
return tmp.groups()[0].strip()
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
|
def getDbServerId():
|
||||||
|
file = getConf()
|
||||||
|
content = mw.readFile(file)
|
||||||
|
rep = 'server-id\s*=\s*(.*)'
|
||||||
|
tmp = re.search(rep, content)
|
||||||
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
def getSocketFile():
|
def getSocketFile():
|
||||||
file = getConf()
|
file = getConf()
|
||||||
content = mw.readFile(file)
|
content = mw.readFile(file)
|
||||||
@@ -123,6 +135,9 @@ def contentReplace(content):
|
|||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
content = content.replace('{$SERVER_PATH}', service_path)
|
||||||
content = content.replace('{$SERVER_APP_PATH}',
|
content = content.replace('{$SERVER_APP_PATH}',
|
||||||
service_path + '/' + getPluginName())
|
service_path + '/' + getPluginName())
|
||||||
|
|
||||||
|
server_id = int(time.time())
|
||||||
|
content = content.replace('{$SERVER_ID}', str(server_id))
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
@@ -640,15 +655,15 @@ def isSqlError(mysqlMsg):
|
|||||||
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||||
if "using password:" in mysqlMsg:
|
if "using password:" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
||||||
if "1045" in mysqlMsg:
|
if "1045," in mysqlMsg:
|
||||||
return mw.returnJson(False, '连接错误!')
|
return mw.returnJson(False, '连接错误!')
|
||||||
if "SQL syntax" in mysqlMsg:
|
if "SQL syntax" in mysqlMsg:
|
||||||
return mw.returnJson(False, 'SQL语法错误!')
|
return mw.returnJson(False, 'SQL语法错误!')
|
||||||
if "Connection refused" in mysqlMsg:
|
if "Connection refused" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||||
if "1133" in mysqlMsg:
|
if "1133," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库用户不存在!')
|
return mw.returnJson(False, '数据库用户不存在!')
|
||||||
if "1007" in mysqlMsg:
|
if "1007," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库已经存在!')
|
return mw.returnJson(False, '数据库已经存在!')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1863,27 +1878,34 @@ def getMasterRepSlaveUserCmd(version):
|
|||||||
|
|
||||||
mode = recognizeDbMode()
|
mode = recognizeDbMode()
|
||||||
|
|
||||||
|
sid = getDbServerId()
|
||||||
|
channel_name = ""
|
||||||
|
if sid != '':
|
||||||
|
channel_name = " for channel 'r{}';".format(sid)
|
||||||
|
|
||||||
if mode == "gtid":
|
if mode == "gtid":
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + "', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
if version == '8.0':
|
if version == '8.0':
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + \
|
||||||
|
"', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
else:
|
else:
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"])
|
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
if version == "8.0":
|
if version == "8.0":
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',SOURCE_LOG_POS=" + str(mstatus[0]["Position"])
|
"',SOURCE_LOG_POS=" + \
|
||||||
|
str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
data['cmd'] = sql
|
data['cmd'] = sql
|
||||||
@@ -2154,22 +2176,10 @@ def updateSlaveSSH(version=''):
|
|||||||
|
|
||||||
|
|
||||||
def getSlaveList(version=''):
|
def getSlaveList(version=''):
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
ret = []
|
|
||||||
for x in range(0, len(dlist)):
|
|
||||||
tmp = {}
|
|
||||||
tmp['Master_User'] = dlist[x]["Master_User"]
|
|
||||||
tmp['Master_Host'] = dlist[x]["Master_Host"]
|
|
||||||
tmp['Master_Port'] = dlist[x]["Master_Port"]
|
|
||||||
tmp['Master_Log_File'] = dlist[x]["Master_Log_File"]
|
|
||||||
tmp['Slave_IO_Running'] = dlist[x]["Slave_IO_Running"]
|
|
||||||
tmp['Slave_SQL_Running'] = dlist[x]["Slave_SQL_Running"]
|
|
||||||
ret.append(tmp)
|
|
||||||
data = {}
|
data = {}
|
||||||
data['data'] = ret
|
data['data'] = dlist
|
||||||
|
|
||||||
return mw.getJson(data)
|
return mw.getJson(data)
|
||||||
|
|
||||||
|
|
||||||
@@ -2193,100 +2203,149 @@ def initSlaveStatus(version=''):
|
|||||||
return initSlaveStatusSyncUser(version)
|
return initSlaveStatusSyncUser(version)
|
||||||
|
|
||||||
|
|
||||||
|
def parseSlaveSyncCmd(cmd):
|
||||||
|
a = {}
|
||||||
|
if cmd.lower().find('for') > 0:
|
||||||
|
cmd_tmp = cmd.split('for')
|
||||||
|
cmd = cmd_tmp[0].strip()
|
||||||
|
|
||||||
|
pattern_c = r"channel \'(.*)\';"
|
||||||
|
match_val = re.match(pattern_c, cmd_tmp[1].strip(), re.I)
|
||||||
|
if match_val:
|
||||||
|
m_groups = match_val.groups()
|
||||||
|
a['channel'] = m_groups[0]
|
||||||
|
vlist = cmd.split(',')
|
||||||
|
for i in vlist:
|
||||||
|
tmp = i.strip()
|
||||||
|
tmp_a = tmp.split(" ")
|
||||||
|
real_tmp = tmp_a[len(tmp_a) - 1]
|
||||||
|
kv = real_tmp.split("=")
|
||||||
|
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSyncUser(version=''):
|
def initSlaveStatusSyncUser(version=''):
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
slave_data = conn.field('ip,port,user,pass,mode,cmd').select()
|
||||||
if len(data) < 1:
|
if len(slave_data) < 1:
|
||||||
return mw.returnJson(False, '需要先添加同步用户配置!')
|
return mw.returnJson(False, '需要先添加同步用户配置!')
|
||||||
|
|
||||||
# print(data)
|
# print(data)
|
||||||
db = pMysqlDb()
|
pdb = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
if len(slave_data) == 1:
|
||||||
if len(dlist) > 0:
|
dlist = pdb.query('show slave status')
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
if len(dlist) > 0:
|
||||||
|
return mw.returnJson(False, '已经初始化好了zz...')
|
||||||
u = data
|
|
||||||
|
|
||||||
mode_name = 'classic'
|
|
||||||
if u['mode'] == '1':
|
|
||||||
mode_name = 'gtid'
|
|
||||||
|
|
||||||
|
msg = ''
|
||||||
local_mode = recognizeDbMode()
|
local_mode = recognizeDbMode()
|
||||||
if local_mode != mode_name:
|
for x in range(len(slave_data)):
|
||||||
return mw.returnJson(False, '同步模式不一致!')
|
slave_t = slave_data[x]
|
||||||
|
mode_name = 'classic'
|
||||||
|
base_t = 'IP:' + slave_t['ip'] + ",PORT:" + \
|
||||||
|
slave_t['port'] + ",USER:" + slave_t['user']
|
||||||
|
|
||||||
t = db.query(u['cmd'])
|
if slave_t['mode'] == '1':
|
||||||
# print(t)
|
mode_name = 'gtid'
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
|
||||||
u['user'], u['pass']))
|
if local_mode != mode_name:
|
||||||
return mw.returnJson(True, '初始化成功!')
|
msg += base_t + '->同步模式不一致'
|
||||||
|
continue
|
||||||
|
|
||||||
|
cmd_sql = slave_t['cmd']
|
||||||
|
if cmd_sql == '':
|
||||||
|
msg += base_t + '->同步命令不能为空'
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
pinfo = parseSlaveSyncCmd(cmd_sql)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
|
||||||
|
# print(u['cmd'])
|
||||||
|
t = pdb.query(cmd_sql)
|
||||||
|
isError = isSqlError(t)
|
||||||
|
if isError:
|
||||||
|
return isError
|
||||||
|
|
||||||
|
# pdb.query("start slave user='{}' password='{}';".format(
|
||||||
|
# u['user'], u['pass']))
|
||||||
|
|
||||||
|
pdb.query("start slave")
|
||||||
|
pdb.query("start all slaves")
|
||||||
|
|
||||||
|
if msg == '':
|
||||||
|
msg = '初始化成功!'
|
||||||
|
return mw.returnJson(True, msg)
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSSH(version=''):
|
def initSlaveStatusSSH(version=''):
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
if len(dlist) > 0:
|
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
|
||||||
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
conn = pSqliteDb('slave_id_rsa')
|
||||||
data = conn.field('ip,port,id_rsa').find()
|
ssh_list = conn.field('ip,port,id_rsa,db_user').select()
|
||||||
|
|
||||||
if len(data) < 1:
|
if len(ssh_list) < 1:
|
||||||
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
|
local_mode = recognizeDbMode()
|
||||||
ip = data['ip']
|
|
||||||
master_port = data['port']
|
|
||||||
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
paramiko.util.log_to_file('paramiko.log')
|
paramiko.util.log_to_file('paramiko.log')
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
|
|
||||||
try:
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
for data in ssh_list:
|
||||||
|
ip = data['ip']
|
||||||
|
SSH_PRIVATE_KEY = "/tmp/t_ssh_" + ip + ".txt"
|
||||||
|
master_port = data['port']
|
||||||
|
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
||||||
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
||||||
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
try:
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
||||||
ssh.connect(hostname=ip, port=int(master_port),
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
username='root', pkey=key)
|
ssh.connect(hostname=ip, port=int(master_port),
|
||||||
|
username='root', pkey=key)
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}'
|
db_user = data['db_user']
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql-yum/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
||||||
result = stdout.read()
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = result.decode('utf-8')
|
result = stdout.read()
|
||||||
cmd_data = json.loads(result)
|
result = result.decode('utf-8')
|
||||||
|
if result.strip() == "":
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:获取同步命令失败!')
|
||||||
|
|
||||||
if not cmd_data['status']:
|
cmd_data = json.loads(result)
|
||||||
return mw.returnJson(False, '[主]:' + cmd_data['msg'])
|
if not cmd_data['status']:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg'])
|
||||||
|
|
||||||
local_mode = recognizeDbMode()
|
if local_mode != cmd_data['data']['mode']:
|
||||||
if local_mode != cmd_data['data']['mode']:
|
return mw.returnJson(False, '[主][' + ip + ']:【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
||||||
return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
|
||||||
|
|
||||||
u = cmd_data['data']['info']
|
u = cmd_data['data']['info']
|
||||||
ps = u['username'] + "|" + u['password']
|
|
||||||
conn.where('ip=?', (ip,)).setField('ps', ps)
|
|
||||||
db.query('stop slave')
|
|
||||||
|
|
||||||
# 保证同步IP一致
|
ps = u['username'] + "|" + u['password']
|
||||||
cmd = cmd_data['data']['cmd']
|
print(ps)
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
conn.where('ip=?', (ip,)).setField('ps', ps)
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*)'",
|
db.query('stop slave')
|
||||||
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
# 保证同步IP一致
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*)'",
|
cmd = cmd_data['data']['cmd']
|
||||||
"MASTER_HOST='" + ip + "'", cmd, 1)
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
db.query(cmd)
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
u['username'], u['password']))
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e))
|
|
||||||
|
|
||||||
ssh.close()
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
time.sleep(1)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
db.query(cmd)
|
||||||
|
ssh.close()
|
||||||
|
if os.path.exists(SSH_PRIVATE_KEY):
|
||||||
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:SSH认证配置连接失败!' + str(e))
|
||||||
|
db.query('start slave')
|
||||||
return mw.returnJson(True, '初始化成功!')
|
return mw.returnJson(True, '初始化成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2296,60 +2355,37 @@ def setSlaveStatus(version=''):
|
|||||||
return mw.returnJson(False, '需要先设置同步配置')
|
return mw.returnJson(False, '需要先设置同步配置')
|
||||||
|
|
||||||
mode = mw.readFile(mode_file)
|
mode = mw.readFile(mode_file)
|
||||||
if mode == 'ssh':
|
pdb = pMysqlDb()
|
||||||
return setSlaveStatusSSH(version)
|
dlist = pdb.query('show slave status')
|
||||||
if mode == 'sync-user':
|
|
||||||
return setSlaveStatusSyncUser(version)
|
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSyncUser(version=''):
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
if len(dlist) == 0:
|
||||||
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
for v in dlist:
|
||||||
db.query('stop slave')
|
connection_name = ''
|
||||||
else:
|
cmd = "slave"
|
||||||
ip = dlist[0]['Master_Host']
|
if 'Channel_Name' in v:
|
||||||
conn = pSqliteDb('slave_sync_user')
|
ch_name = v['Channel_Name']
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
cmd = "slave for channel '{}'".format(ch_name)
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
user = data['user']
|
|
||||||
apass = data['pass']
|
|
||||||
|
|
||||||
db.query("start slave")
|
if (v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes'):
|
||||||
# db.query("start slave user='{}' password='{}';".format(user, apass))
|
pdb.query("stop {}".format(cmd))
|
||||||
|
else:
|
||||||
return mw.returnJson(True, '设置成功!')
|
pdb.query("start {}".format(cmd))
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSSH(version=''):
|
|
||||||
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
|
||||||
return mw.returnJson(False, '需要手动添加主服务命令或者执行[初始化]!')
|
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
|
||||||
db.query('stop slave')
|
|
||||||
else:
|
|
||||||
ip = dlist[0]['Master_Host']
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
|
||||||
data = conn.field('ip,ps').where("ip=?", (ip,)).find()
|
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
u = data['ps'].split("|")
|
|
||||||
db.query("start slave user='{}' password='{}';".format(u[0], u[1]))
|
|
||||||
|
|
||||||
return mw.returnJson(True, '设置成功!')
|
return mw.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
|
||||||
def deleteSlave(version=''):
|
def deleteSlave(version=''):
|
||||||
|
args = getArgs()
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('stop slave')
|
if 'sign' in args:
|
||||||
dlist = db.query('reset slave all')
|
sign = args['sign']
|
||||||
|
db.query("stop slave for channel '{}'".format(sign))
|
||||||
|
db.query("reset slave all for channel '{}'".format(sign))
|
||||||
|
else:
|
||||||
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
return mw.returnJson(True, '删除成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2385,11 +2421,13 @@ def dumpMysqlData(version=''):
|
|||||||
|
|
||||||
############### --- 重要 同步---- ###########
|
############### --- 重要 同步---- ###########
|
||||||
|
|
||||||
|
def asyncTmpfile():
|
||||||
|
path = '/tmp/mysql_yum_async_status.txt'
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def writeDbSyncStatus(data):
|
def writeDbSyncStatus(data):
|
||||||
path = '/tmp/db_async_status.txt'
|
path = asyncTmpfile()
|
||||||
# status_data['code'] = 1
|
|
||||||
# status_data['msg'] = '主服务器备份完成...'
|
|
||||||
# status_data['progress'] = 30
|
|
||||||
mw.writeFile(path, json.dumps(data))
|
mw.writeFile(path, json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
@@ -2407,16 +2445,22 @@ def doFullSync(version=''):
|
|||||||
|
|
||||||
def doFullSyncUser(version=''):
|
def doFullSyncUser(version=''):
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
sync_db = args['db']
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
if sync_sign != '':
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
||||||
|
|
||||||
user = data['user']
|
user = data['user']
|
||||||
apass = data['pass']
|
apass = data['pass']
|
||||||
port = data['port']
|
port = data['port']
|
||||||
@@ -2433,16 +2477,17 @@ def doFullSyncUser(version=''):
|
|||||||
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
|
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
|
||||||
|
|
||||||
if not os.path.exists(bak_file):
|
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" + \
|
dump_sql_data = getServerDir() + "/bin/usr/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
|
||||||
port + " -u" + user + " -p" + apass + \
|
port + " -u" + user + " -p\"" + apass + \
|
||||||
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
|
"\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
|
||||||
|
# print(dump_sql_data)
|
||||||
mw.execShell(dump_sql_data)
|
mw.execShell(dump_sql_data)
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
|
||||||
if os.path.exists(bak_file):
|
if os.path.exists(bak_file):
|
||||||
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||||
sock = getSocketFile()
|
sock = getSocketFile()
|
||||||
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
|
my_import_cmd = getServerDir() + '/bin/usr/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
|
||||||
' ' + sync_db + ' < ' + bak_file
|
' ' + sync_db + ' < ' + bak_file
|
||||||
mw.execShell(my_import_cmd)
|
mw.execShell(my_import_cmd)
|
||||||
|
|
||||||
@@ -2452,21 +2497,30 @@ def doFullSyncUser(version=''):
|
|||||||
db.query("start slave")
|
db.query("start slave")
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
os.system("rm -rf " + bak_file)
|
|
||||||
|
if os.path.exists(bak_file):
|
||||||
|
os.system("rm -rf " + bak_file)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def doFullSyncSSH(version=''):
|
def doFullSyncSSH(version=''):
|
||||||
|
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
||||||
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
if sync_sign != '':
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
||||||
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
||||||
@@ -2508,7 +2562,8 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
||||||
|
|
||||||
dbname = args['db']
|
dbname = args['db']
|
||||||
cmd = "cd /www/server/mdserver-web && python3 plugins/mysql/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
cmd = "cd /www/server/mdserver-web && source bin/activate && python3 " + \
|
||||||
|
getSPluginDir() + "/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
||||||
print(cmd)
|
print(cmd)
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
@@ -2531,7 +2586,10 @@ def doFullSyncSSH(version=''):
|
|||||||
if copy_status == None:
|
if copy_status == None:
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \
|
||||||
|
getSPluginDir() + \
|
||||||
|
'/index.py get_master_rep_slave_user_cmd {"username":"' + \
|
||||||
|
db_user + '","db":""}'
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
result = result.decode('utf-8')
|
result = result.decode('utf-8')
|
||||||
@@ -2543,10 +2601,12 @@ def doFullSyncSSH(version=''):
|
|||||||
cmd = cmd_data['data']['cmd']
|
cmd = cmd_data['data']['cmd']
|
||||||
# 保证同步IP一致
|
# 保证同步IP一致
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
|
||||||
db.query(cmd)
|
db.query(cmd)
|
||||||
uinfo = cmd_data['data']['info']
|
uinfo = cmd_data['data']['info']
|
||||||
@@ -2558,8 +2618,10 @@ def doFullSyncSSH(version=''):
|
|||||||
root_dir = getServerDir()
|
root_dir = getServerDir()
|
||||||
msock = root_dir + "/mysql.sock"
|
msock = root_dir + "/mysql.sock"
|
||||||
mw.execShell("cd /tmp && gzip -d dump.sql.gz")
|
mw.execShell("cd /tmp && gzip -d dump.sql.gz")
|
||||||
cmd = root_dir + "/bin/mysql -S " + msock + \
|
cmd = root_dir + "/bin/usr/bin/mysql -S " + msock + \
|
||||||
" -uroot -p" + pwd + " < /tmp/dump.sql"
|
" -uroot -p" + pwd + " < /tmp/dump.sql"
|
||||||
|
|
||||||
|
print(cmd)
|
||||||
import_data = mw.execShell(cmd)
|
import_data = mw.execShell(cmd)
|
||||||
if import_data[0] == '':
|
if import_data[0] == '':
|
||||||
print(import_data[1])
|
print(import_data[1])
|
||||||
@@ -2569,8 +2631,9 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
# "start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password'])
|
||||||
uinfo['username'], uinfo['password']))
|
|
||||||
|
db.query("start slave")
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
|
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
@@ -2584,12 +2647,16 @@ def fullSync(version=''):
|
|||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
status_file = '/tmp/db_async_status.txt'
|
sign = ''
|
||||||
|
if 'sign' in args:
|
||||||
|
sign = args['sign']
|
||||||
|
|
||||||
|
status_file = asyncTmpfile()
|
||||||
if args['begin'] == '1':
|
if args['begin'] == '1':
|
||||||
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + getPluginDir() + \
|
||||||
getPluginDir() + \
|
'/index.py do_full_sync {"db":"' + \
|
||||||
'/index.py do_full_sync {"db":"' + args['db'] + '"} &'
|
args['db'] + '","sign":"' + sign + '"} &'
|
||||||
print(cmd)
|
# print(cmd)
|
||||||
mw.execShell(cmd)
|
mw.execShell(cmd)
|
||||||
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
||||||
|
|
||||||
|
|||||||
@@ -162,34 +162,6 @@ function myPort(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//数据库存储信置
|
|
||||||
function changeMySQLDataPath(act) {
|
|
||||||
if (act != undefined) {
|
|
||||||
layer.confirm(lan.soft.mysql_to_msg, { closeBtn: 2, icon: 3 }, function() {
|
|
||||||
var datadir = $("#datadir").val();
|
|
||||||
var data = 'datadir=' + datadir;
|
|
||||||
var loadT = layer.msg(lan.soft.mysql_to_msg1, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
|
||||||
$.post('/database?action=SetDataDir', data, function(rdata) {
|
|
||||||
layer.close(loadT)
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/database?action=GetMySQLInfo', '', function(rdata) {
|
|
||||||
var LimitCon = '<p class="conf_p">\
|
|
||||||
<input id="datadir" class="phpUploadLimit bt-input-text mr5" style="width:350px;" type="text" value="' + rdata.datadir + '" name="datadir">\
|
|
||||||
<span onclick="ChangePath(\'datadir\')" class="glyphicon glyphicon-folder-open cursor mr20" style="width:auto"></span><button class="btn btn-success btn-sm" onclick="changeMySQLDataPath(1)">' + lan.soft.mysql_to + '</button>\
|
|
||||||
</p>';
|
|
||||||
$(".soft-man-con").html(LimitCon);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//数据库配置状态
|
//数据库配置状态
|
||||||
function myPerfOpt() {
|
function myPerfOpt() {
|
||||||
//获取MySQL配置
|
//获取MySQL配置
|
||||||
@@ -1691,12 +1663,12 @@ function getMasterRepSlaveListPage(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteSlave(){
|
function deleteSlave(sign){
|
||||||
myPost('delete_slave', {}, function(data){
|
myPost('delete_slave', {sign:sign}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
showMsg(rdata['msg'], function(){
|
showMsg(rdata['msg'], function(){
|
||||||
masterOrSlaveConf();
|
masterOrSlaveConf();
|
||||||
},{},3000);
|
},{icon:rdata.status?1:2,time:3000},3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1704,28 +1676,73 @@ function deleteSlave(){
|
|||||||
function getFullSyncStatus(db){
|
function getFullSyncStatus(db){
|
||||||
var timeId = null;
|
var timeId = null;
|
||||||
|
|
||||||
var btn = '<div class="table_toolbar" style="left:0px;"><span data-status="init" class="sync btn btn-default btn-sm" id="begin_full_sync" title="">开始</span></div>';
|
myPost('get_slave_list', {page:1,page_size:100}, function(data){
|
||||||
var loadOpen = layer.open({
|
var rdata = $.parseJSON(data.data);
|
||||||
type: 1,
|
var rsource = rdata.data;
|
||||||
title: '全量同步['+db+']',
|
|
||||||
area: '500px',
|
if (db == 'ALL' && rsource.length>1){
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
layer.msg("多主不支持该模式!",{icon:2});
|
||||||
<div class='divtable mtb10'>\
|
return;
|
||||||
<span id='full_msg'></span>\
|
|
||||||
<div class='progress'>\
|
|
||||||
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
"+btn+"\
|
|
||||||
</div>",
|
|
||||||
cancel: function(){
|
|
||||||
clearInterval(timeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dataSource = '';
|
||||||
|
if (rsource.length>1){
|
||||||
|
var sourceList = '';
|
||||||
|
for (var i = 0; i < rsource.length; i++) {
|
||||||
|
if ('Channel_Name' in rsource[i]){
|
||||||
|
sourceList += '<option val="'+rsource[i]['Master_Host']+'">'+rsource[i]['Master_Host']+'</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource = "<p class='line' style='text-align:center;'>\
|
||||||
|
<span>同步数据源:</span>\
|
||||||
|
<select class='bt-input-text' name='data_source' style='width:200px;'>" + sourceList + "</select>\
|
||||||
|
</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '全量同步['+db+']',
|
||||||
|
area: '500px',
|
||||||
|
content:"<div class='bt-form pd15'>\
|
||||||
|
<div class='divtable mtb10'>\
|
||||||
|
"+dataSource+"\
|
||||||
|
<span id='full_msg'></span>\
|
||||||
|
<div class='progress'>\
|
||||||
|
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class='table_toolbar' style='left:0px;'>\
|
||||||
|
<span data-status='init' class='sync btn btn-default btn-sm' id='begin_full_sync'>开始</span>\
|
||||||
|
</div>\
|
||||||
|
</div>",
|
||||||
|
cancel: function(){
|
||||||
|
clearInterval(timeId);
|
||||||
|
},
|
||||||
|
success:function(){
|
||||||
|
$('#begin_full_sync').click(function(){
|
||||||
|
var val = $(this).data('status');
|
||||||
|
var sign = '';
|
||||||
|
if (dataSource !=''){
|
||||||
|
sign = $('select[name="data_source"]').val();
|
||||||
|
}
|
||||||
|
if (val == 'init'){
|
||||||
|
fullSync(db, sign, 1);
|
||||||
|
timeId = setInterval(function(){
|
||||||
|
fullSync(db,sign,0);
|
||||||
|
}, 1000);
|
||||||
|
$(this).data('status','starting');
|
||||||
|
} else {
|
||||||
|
layer.msg("正在同步中..",{icon:0});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function fullSync(db,begin){
|
function fullSync(db,sign,begin){
|
||||||
|
|
||||||
myPostN('full_sync', {db:db,begin:begin}, function(data){
|
myPostN('full_sync', {db:db,sign:sign,begin:begin}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
$('#full_msg').text(rdata['msg']);
|
$('#full_msg').text(rdata['msg']);
|
||||||
$('.progress-bar').css('width',rdata['progress']+'%');
|
$('.progress-bar').css('width',rdata['progress']+'%');
|
||||||
@@ -1738,19 +1755,6 @@ function getFullSyncStatus(db){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#begin_full_sync').click(function(){
|
|
||||||
var val = $(this).attr('data-status');
|
|
||||||
if (val == 'init'){
|
|
||||||
fullSync(db,1);
|
|
||||||
timeId = setInterval(function(){
|
|
||||||
fullSync(db,0);
|
|
||||||
}, 1000);
|
|
||||||
$(this).attr('data-status','starting');
|
|
||||||
} else {
|
|
||||||
layer.msg("正在同步中..");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSlaveSSH(ip=''){
|
function addSlaveSSH(ip=''){
|
||||||
@@ -1920,18 +1924,29 @@ function addSlaveSyncUser(ip=''){
|
|||||||
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
||||||
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
||||||
<div class='line'>\
|
<div class='line'>\
|
||||||
<span class='tname'>CMD[最好填好]</span>\
|
<span class='tname'>CMD[必须填写]</span>\
|
||||||
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<input type='hidden' name='mode' value='"+mode+"' />\
|
<input type='hidden' name='mode' value='"+mode+"' />\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
$('textarea[name="cmd"]').html(cmd);
|
$('textarea[name="cmd"]').html(cmd);
|
||||||
|
|
||||||
$('textarea[name="cmd"]').change(function(){
|
$('textarea[name="cmd"]').change(function(){
|
||||||
var val = $(this).val();
|
var val = $(this).val();
|
||||||
var vlist = val.split(',');
|
|
||||||
var a = {};
|
var a = {};
|
||||||
|
if (val.toLowerCase().indexOf('for')>0){
|
||||||
|
cmd_tmp = val.split('for');
|
||||||
|
val = cmd_tmp[0].trim();
|
||||||
|
|
||||||
|
const channel_str = cmd_tmp[1].trim();
|
||||||
|
const ch_reg = /channel \'(.*)\';/;
|
||||||
|
var match_val = channel_str.match(ch_reg);
|
||||||
|
if (match_val.length>1){
|
||||||
|
a['channel'] = match_val[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlist = val.split(',');
|
||||||
for (var i in vlist) {
|
for (var i in vlist) {
|
||||||
var tmp = toTrim(vlist[i]);
|
var tmp = toTrim(vlist[i]);
|
||||||
var tmp_a = tmp.split(" ");
|
var tmp_a = tmp.split(" ");
|
||||||
@@ -2098,7 +2113,7 @@ function getSlaveUserList(){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步账户列表',
|
title: '同步账户列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2122,7 +2137,7 @@ function getSlaveSSHList(page=1){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: 'SSH列表',
|
title: 'SSH列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2230,10 +2245,16 @@ function masterOrSlaveConf(version=''){
|
|||||||
myPost('get_slave_list', _data, function(data){
|
myPost('get_slave_list', _data, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
var list = '';
|
var list = '';
|
||||||
|
|
||||||
|
var isHasSign = false;
|
||||||
for(i in rdata.data){
|
for(i in rdata.data){
|
||||||
|
|
||||||
var v = rdata.data[i];
|
var v = rdata.data[i];
|
||||||
var status = "<a class='btlink db_error'>异常</>";
|
if ('Channel_Name' in v){
|
||||||
|
isHasSign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = "<a data-id="+i+" class='btlink db_error'>异常</>";
|
||||||
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
||||||
status = "正常";
|
status = "正常";
|
||||||
}
|
}
|
||||||
@@ -2245,13 +2266,23 @@ function masterOrSlaveConf(version=''){
|
|||||||
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
||||||
|
|
||||||
|
if (isHasSign){
|
||||||
|
list += '<td>' + v['Channel_Name'] +'</td>';
|
||||||
|
}
|
||||||
|
|
||||||
list += '<td>' + status +'</td>';
|
list += '<td>' + status +'</td>';
|
||||||
list += '<td style="text-align:right">' +
|
list += '<td style="text-align:right">' +
|
||||||
'<a href="javascript:;" class="btlink" onclick="deleteSlave()" title="删除">删除</a>' +
|
'<a data-id="'+i+'" href="javascript:;" class="btlink btn_delete_slave" title="删除">删除</a>' +
|
||||||
'</td>';
|
'</td>';
|
||||||
list += '</tr>';
|
list += '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var signThead_th = '';
|
||||||
|
if (isHasSign){
|
||||||
|
var signThead_th = '<th>标识</th>';
|
||||||
|
}
|
||||||
|
|
||||||
var con = '<div class="divtable mtb10">\
|
var con = '<div class="divtable mtb10">\
|
||||||
<div class="tablescroll">\
|
<div class="tablescroll">\
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||||
@@ -2262,6 +2293,7 @@ function masterOrSlaveConf(version=''){
|
|||||||
<th>日志</th>\
|
<th>日志</th>\
|
||||||
<th>IO</th>\
|
<th>IO</th>\
|
||||||
<th>SQL</th>\
|
<th>SQL</th>\
|
||||||
|
'+signThead_th+'\
|
||||||
<th>状态</th>\
|
<th>状态</th>\
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
<th style="text-align:right;">操作</th></tr></thead>\
|
||||||
<tbody>\
|
<tbody>\
|
||||||
@@ -2276,22 +2308,74 @@ function masterOrSlaveConf(version=''){
|
|||||||
// </div>
|
// </div>
|
||||||
$(".table_slave_status_list").html(con);
|
$(".table_slave_status_list").html(con);
|
||||||
|
|
||||||
$('.db_error').click(function(){
|
$(".btn_delete_slave").click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var v = rdata.data[id];
|
||||||
|
if ('Channel_Name' in v){
|
||||||
|
deleteSlave(v['Channel_Name']);
|
||||||
|
} else{
|
||||||
|
deleteSlave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.db_error').click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var info = rdata.data[id];
|
||||||
|
|
||||||
|
var err_line = "";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>IO错误</td>\
|
||||||
|
<td>"+ (info['Last_IO_Error'] == '' ? '无':info['Last_IO_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>SQL错误</td>\
|
||||||
|
<td>"+(info['Last_SQL_Error'] == '' ? '无':info['Last_SQL_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>状态</td>\
|
||||||
|
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步异常信息',
|
title: '同步异常信息',
|
||||||
area: '500px',
|
area: ['600px','300px'],
|
||||||
content:"<form class='bt-form pd20 pb70'>\
|
btn:['复制错误',"取消"],
|
||||||
<div class='line'>"+v['Error']+"</div>\
|
content:"<form class='bt-form pd15'>\
|
||||||
<div class='bt-form-submit-btn'>\
|
<div class='divtable mtb10'>\
|
||||||
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
|
<div class='tablescroll'>\
|
||||||
|
<table class='table table-hover' width='100%' cellspacing='0' cellpadding='0' border='0' style='border: 0 none;'>\
|
||||||
|
<thead><tr>\
|
||||||
|
<th style='width:80px;'>类型</th>\
|
||||||
|
<th>内容</th>\
|
||||||
|
</tr></thead>\
|
||||||
|
<tbody>"+ err_line +"</tbody>\
|
||||||
|
</table>\
|
||||||
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
$('.class-copy-db-err').click(function(){
|
// $('.class-copy-db-err').click(function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
});
|
// });
|
||||||
|
},
|
||||||
|
yes:function(){
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ basedir = {$SERVER_APP_PATH}
|
|||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
server-id = {$SERVER_ID}
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ basedir = {$SERVER_APP_PATH}
|
|||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
server-id = {$SERVER_ID}
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
explicit_defaults_for_timestamp=true
|
explicit_defaults_for_timestamp=true
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
@@ -80,6 +81,8 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ basedir = {$SERVER_APP_PATH}
|
|||||||
datadir = {$SERVER_APP_PATH}/data
|
datadir = {$SERVER_APP_PATH}/data
|
||||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||||
server-id = {$SERVER_ID}
|
server-id = {$SERVER_ID}
|
||||||
|
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
default_storage_engine = InnoDB
|
default_storage_engine = InnoDB
|
||||||
|
|
||||||
@@ -77,6 +78,8 @@ replicate-ignore-db = performance_schema
|
|||||||
replicate-ignore-db = mysql
|
replicate-ignore-db = mysql
|
||||||
replicate-ignore-db = test
|
replicate-ignore-db = test
|
||||||
|
|
||||||
|
master_info_repository = table
|
||||||
|
relay_log_info_repository = table
|
||||||
|
|
||||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||||
innodb_data_file_path = ibdata1:10M:autoextend
|
innodb_data_file_path = ibdata1:10M:autoextend
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<p onclick="dbList()">管理列表</p>
|
<p onclick="dbList()">管理列表</p>
|
||||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bt-w-con pd15">
|
<div class="bt-w-con pd15" style="height:555px;overflow: auto;">
|
||||||
<div class="soft-man-con"></div>
|
<div class="soft-man-con"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+211
-178
@@ -36,6 +36,10 @@ def getPluginDir():
|
|||||||
return mw.getPluginDir() + '/' + getPluginName()
|
return mw.getPluginDir() + '/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
|
def getSPluginDir():
|
||||||
|
return '/www/server/mdserver-web/plugins/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
def getServerDir():
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
return mw.getServerDir() + '/' + getPluginName()
|
||||||
|
|
||||||
@@ -85,6 +89,14 @@ def getDbPort():
|
|||||||
return tmp.groups()[0].strip()
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
|
def getDbServerId():
|
||||||
|
file = getConf()
|
||||||
|
content = mw.readFile(file)
|
||||||
|
rep = 'server-id\s*=\s*(.*)'
|
||||||
|
tmp = re.search(rep, content)
|
||||||
|
return tmp.groups()[0].strip()
|
||||||
|
|
||||||
|
|
||||||
def getSocketFile():
|
def getSocketFile():
|
||||||
file = getConf()
|
file = getConf()
|
||||||
content = mw.readFile(file)
|
content = mw.readFile(file)
|
||||||
@@ -802,15 +814,15 @@ def isSqlError(mysqlMsg):
|
|||||||
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||||
if "using password:" in mysqlMsg:
|
if "using password:" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
return mw.returnJson(False, '数据库密码错误,在管理列表-点击【修复】!')
|
||||||
if "1045" in mysqlMsg:
|
if "1045," in mysqlMsg:
|
||||||
return mw.returnJson(False, '连接错误!')
|
return mw.returnJson(False, '连接错误!')
|
||||||
if "SQL syntax" in mysqlMsg:
|
if "SQL syntax" in mysqlMsg:
|
||||||
return mw.returnJson(False, 'SQL语法错误!')
|
return mw.returnJson(False, 'SQL语法错误!')
|
||||||
if "Connection refused" in mysqlMsg:
|
if "Connection refused" in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||||
if "1133" in mysqlMsg:
|
if "1133," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库用户不存在!')
|
return mw.returnJson(False, '数据库用户不存在!')
|
||||||
if "1007" in mysqlMsg:
|
if "1007," in mysqlMsg:
|
||||||
return mw.returnJson(False, '数据库已经存在!')
|
return mw.returnJson(False, '数据库已经存在!')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1887,13 +1899,14 @@ def getMasterStatus(version=''):
|
|||||||
data = {}
|
data = {}
|
||||||
data['mode'] = recognizeDbMode()
|
data['mode'] = recognizeDbMode()
|
||||||
data['status'] = master_status
|
data['status'] = master_status
|
||||||
|
data['slave_status'] = False
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
|
|
||||||
# print(dlist[0])
|
for v in dlist:
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
if v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes':
|
||||||
data['slave_status'] = True
|
data['slave_status'] = True
|
||||||
|
|
||||||
return mw.returnJson(master_status, '设置成功', data)
|
return mw.returnJson(master_status, '设置成功', data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2057,27 +2070,34 @@ def getMasterRepSlaveUserCmd(version):
|
|||||||
|
|
||||||
mode = recognizeDbMode()
|
mode = recognizeDbMode()
|
||||||
|
|
||||||
|
sid = getDbServerId()
|
||||||
|
channel_name = ""
|
||||||
|
if sid != '':
|
||||||
|
channel_name = " for channel 'r{}';".format(sid)
|
||||||
|
|
||||||
if mode == "gtid":
|
if mode == "gtid":
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + "', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
if version == '8.0':
|
if version == '8.0':
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + "', MASTER_AUTO_POSITION=1"
|
clist[0]['password'] + \
|
||||||
|
"', MASTER_AUTO_POSITION=1" + channel_name
|
||||||
else:
|
else:
|
||||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"])
|
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
if version == "8.0":
|
if version == "8.0":
|
||||||
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
|
||||||
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
|
||||||
clist[0]['password'] + \
|
clist[0]['password'] + \
|
||||||
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
|
||||||
"',SOURCE_LOG_POS=" + str(mstatus[0]["Position"])
|
"',SOURCE_LOG_POS=" + \
|
||||||
|
str(mstatus[0]["Position"]) + channel_name
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
data['cmd'] = sql
|
data['cmd'] = sql
|
||||||
@@ -2348,48 +2368,17 @@ def updateSlaveSSH(version=''):
|
|||||||
|
|
||||||
|
|
||||||
def getSlaveList(version=''):
|
def getSlaveList(version=''):
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
ret = []
|
|
||||||
for x in range(0, len(dlist)):
|
|
||||||
tmp = {}
|
|
||||||
tmp['Master_User'] = dlist[x]["Master_User"]
|
|
||||||
tmp['Master_Host'] = dlist[x]["Master_Host"]
|
|
||||||
tmp['Master_Port'] = dlist[x]["Master_Port"]
|
|
||||||
tmp['Master_Log_File'] = dlist[x]["Master_Log_File"]
|
|
||||||
tmp['Slave_IO_Running'] = dlist[x]["Slave_IO_Running"]
|
|
||||||
tmp['Slave_SQL_Running'] = dlist[x]["Slave_SQL_Running"]
|
|
||||||
tmp['Last_Error'] = dlist[x]["Last_Error"]
|
|
||||||
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
|
|
||||||
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
|
|
||||||
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
|
|
||||||
|
|
||||||
tmp['Error'] = ''
|
|
||||||
if tmp['Last_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_Error']
|
|
||||||
|
|
||||||
if tmp['Last_IO_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_IO_Error']
|
|
||||||
|
|
||||||
if tmp['Last_SQL_Error'] != '':
|
|
||||||
tmp['Error'] = tmp['Last_SQL_Error']
|
|
||||||
|
|
||||||
if tmp['Error'] == '':
|
|
||||||
tmp['Error'] = tmp['Slave_SQL_Running_State']
|
|
||||||
|
|
||||||
ret.append(tmp)
|
|
||||||
data = {}
|
data = {}
|
||||||
data['data'] = ret
|
data['data'] = dlist
|
||||||
|
|
||||||
return mw.getJson(data)
|
return mw.getJson(data)
|
||||||
|
|
||||||
|
|
||||||
def getSlaveSyncCmd(version=''):
|
def getSlaveSyncCmd(version=''):
|
||||||
|
|
||||||
root = mw.getRunDir()
|
root = mw.getRunDir()
|
||||||
cmd = 'cd ' + root + ' && python3 ' + root + \
|
cmd = 'cd ' + root + ' && python3 ' + root + \
|
||||||
'/plugins/mysql/index.py do_full_sync {"db":"all"}'
|
'/plugins/mysql/index.py do_full_sync {"db":"all","sign",""}'
|
||||||
return mw.returnJson(True, 'ok', cmd)
|
return mw.returnJson(True, 'ok', cmd)
|
||||||
|
|
||||||
|
|
||||||
@@ -2424,111 +2413,152 @@ def makeSyncUsercmd(u, version=''):
|
|||||||
return sql
|
return sql
|
||||||
|
|
||||||
|
|
||||||
|
def parseSlaveSyncCmd(cmd):
|
||||||
|
a = {}
|
||||||
|
if cmd.lower().find('for') > 0:
|
||||||
|
cmd_tmp = cmd.split('for')
|
||||||
|
cmd = cmd_tmp[0].strip()
|
||||||
|
|
||||||
|
pattern_c = r"channel \'(.*)\';"
|
||||||
|
match_val = re.match(pattern_c, cmd_tmp[1].strip(), re.I)
|
||||||
|
if match_val:
|
||||||
|
m_groups = match_val.groups()
|
||||||
|
a['channel'] = m_groups[0]
|
||||||
|
vlist = cmd.split(',')
|
||||||
|
for i in vlist:
|
||||||
|
tmp = i.strip()
|
||||||
|
tmp_a = tmp.split(" ")
|
||||||
|
real_tmp = tmp_a[len(tmp_a) - 1]
|
||||||
|
kv = real_tmp.split("=")
|
||||||
|
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSyncUser(version=''):
|
def initSlaveStatusSyncUser(version=''):
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
slave_data = conn.field('ip,port,user,pass,mode,cmd').select()
|
||||||
if len(data) < 1:
|
if len(slave_data) < 1:
|
||||||
return mw.returnJson(False, '需要先添加同步用户配置!')
|
return mw.returnJson(False, '需要先添加同步用户配置!')
|
||||||
|
|
||||||
# print(data)
|
# print(data)
|
||||||
db = pMysqlDb()
|
pdb = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
if len(slave_data) == 1:
|
||||||
if len(dlist) > 0:
|
dlist = pdb.query('show slave status')
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
if len(dlist) > 0:
|
||||||
|
return mw.returnJson(False, '已经初始化好了zz...')
|
||||||
u = data
|
|
||||||
|
|
||||||
mode_name = 'classic'
|
|
||||||
if u['mode'] == '1':
|
|
||||||
mode_name = 'gtid'
|
|
||||||
|
|
||||||
|
msg = ''
|
||||||
local_mode = recognizeDbMode()
|
local_mode = recognizeDbMode()
|
||||||
if local_mode != mode_name:
|
for x in range(len(slave_data)):
|
||||||
return mw.returnJson(False, '同步模式不一致!')
|
slave_t = slave_data[x]
|
||||||
|
mode_name = 'classic'
|
||||||
|
base_t = 'IP:' + slave_t['ip'] + ",PORT:" + \
|
||||||
|
slave_t['port'] + ",USER:" + slave_t['user']
|
||||||
|
|
||||||
if u['cmd'] == '' and local_mode == 'gtid':
|
if slave_t['mode'] == '1':
|
||||||
sql = makeSyncUsercmd(u, version)
|
mode_name = 'gtid'
|
||||||
# print(sql)
|
|
||||||
t = db.query(sql)
|
if local_mode != mode_name:
|
||||||
else:
|
msg += base_t + '->同步模式不一致'
|
||||||
if u['cmd'] == '':
|
continue
|
||||||
return mw.returnJson(False, '经典模式下,必须手写同步命令!')
|
|
||||||
|
cmd_sql = slave_t['cmd']
|
||||||
|
if cmd_sql == '':
|
||||||
|
msg += base_t + '->同步命令不能为空'
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
pinfo = parseSlaveSyncCmd(cmd_sql)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
|
||||||
# print(u['cmd'])
|
# print(u['cmd'])
|
||||||
t = db.query(u['cmd'])
|
t = pdb.query(cmd_sql)
|
||||||
isError = isSqlError(t)
|
isError = isSqlError(t)
|
||||||
if isError:
|
if isError:
|
||||||
return isError
|
return isError
|
||||||
|
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
# pdb.query("start slave user='{}' password='{}';".format(
|
||||||
u['user'], u['pass']))
|
# u['user'], u['pass']))
|
||||||
return mw.returnJson(True, '初始化成功!')
|
|
||||||
|
pdb.query("start slave")
|
||||||
|
pdb.query("start all slaves")
|
||||||
|
|
||||||
|
if msg == '':
|
||||||
|
msg = '初始化成功!'
|
||||||
|
return mw.returnJson(True, msg)
|
||||||
|
|
||||||
|
|
||||||
def initSlaveStatusSSH(version=''):
|
def initSlaveStatusSSH(version=''):
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('show slave status')
|
dlist = db.query('show slave status')
|
||||||
if len(dlist) > 0:
|
|
||||||
return mw.returnJson(False, '已经初始化好了zz...')
|
|
||||||
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
conn = pSqliteDb('slave_id_rsa')
|
||||||
data = conn.field('ip,port,id_rsa').find()
|
ssh_list = conn.field('ip,port,id_rsa,db_user').select()
|
||||||
|
|
||||||
if len(data) < 1:
|
if len(ssh_list) < 1:
|
||||||
return mw.returnJson(False, '需要先添加SSH配置!')
|
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
|
local_mode = recognizeDbMode()
|
||||||
ip = data['ip']
|
|
||||||
master_port = data['port']
|
|
||||||
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
paramiko.util.log_to_file('paramiko.log')
|
paramiko.util.log_to_file('paramiko.log')
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
|
|
||||||
try:
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
for data in ssh_list:
|
||||||
|
ip = data['ip']
|
||||||
|
SSH_PRIVATE_KEY = "/tmp/t_ssh_" + ip + ".txt"
|
||||||
|
master_port = data['port']
|
||||||
|
mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
|
||||||
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
|
||||||
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
try:
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
|
||||||
ssh.connect(hostname=ip, port=int(master_port),
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
username='root', pkey=key)
|
ssh.connect(hostname=ip, port=int(master_port),
|
||||||
|
username='root', pkey=key)
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}'
|
db_user = data['db_user']
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \
|
||||||
result = stdout.read()
|
getSPluginDir() + \
|
||||||
result = result.decode('utf-8')
|
'/index.py get_master_rep_slave_user_cmd {"username":"' + \
|
||||||
cmd_data = json.loads(result)
|
db_user + '","db":""}'
|
||||||
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
|
result = stdout.read()
|
||||||
|
result = result.decode('utf-8')
|
||||||
|
if result.strip() == "":
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:获取同步命令失败!')
|
||||||
|
|
||||||
if not cmd_data['status']:
|
cmd_data = json.loads(result)
|
||||||
return mw.returnJson(False, '[主]:' + cmd_data['msg'])
|
if not cmd_data['status']:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg'])
|
||||||
|
|
||||||
local_mode = recognizeDbMode()
|
if local_mode != cmd_data['data']['mode']:
|
||||||
if local_mode != cmd_data['data']['mode']:
|
return mw.returnJson(False, '[主][' + ip + ']:【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
||||||
return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
|
|
||||||
|
|
||||||
u = cmd_data['data']['info']
|
u = cmd_data['data']['info']
|
||||||
ps = u['username'] + "|" + u['password']
|
|
||||||
conn.where('ip=?', (ip,)).setField('ps', ps)
|
|
||||||
db.query('stop slave')
|
|
||||||
|
|
||||||
# 保证同步IP一致
|
ps = u['username'] + "|" + u['password']
|
||||||
cmd = cmd_data['data']['cmd']
|
print(ps)
|
||||||
if cmd.find('SOURCE_HOST') > -1:
|
conn.where('ip=?', (ip,)).setField('ps', ps)
|
||||||
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
db.query('stop slave')
|
||||||
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
|
||||||
|
|
||||||
if cmd.find('MASTER_HOST') > -1:
|
# 保证同步IP一致
|
||||||
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
cmd = cmd_data['data']['cmd']
|
||||||
"MASTER_HOST='" + ip + "'", cmd, 1)
|
if cmd.find('SOURCE_HOST') > -1:
|
||||||
db.query(cmd)
|
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
"SOURCE_HOST='" + ip + "'", cmd, 1)
|
||||||
u['username'], u['password']))
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e))
|
|
||||||
|
|
||||||
ssh.close()
|
if cmd.find('MASTER_HOST') > -1:
|
||||||
time.sleep(1)
|
cmd = re.sub(r"MASTER_HOST='(.*?)'",
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
"MASTER_HOST='" + ip + "'", cmd, 1)
|
||||||
|
db.query(cmd)
|
||||||
|
ssh.close()
|
||||||
|
if os.path.exists(SSH_PRIVATE_KEY):
|
||||||
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
|
except Exception as e:
|
||||||
|
return mw.returnJson(False, '[主][' + ip + ']:SSH认证配置连接失败!' + str(e))
|
||||||
|
db.query('start slave')
|
||||||
return mw.returnJson(True, '初始化成功!')
|
return mw.returnJson(True, '初始化成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2538,60 +2568,37 @@ def setSlaveStatus(version=''):
|
|||||||
return mw.returnJson(False, '需要先设置同步配置')
|
return mw.returnJson(False, '需要先设置同步配置')
|
||||||
|
|
||||||
mode = mw.readFile(mode_file)
|
mode = mw.readFile(mode_file)
|
||||||
if mode == 'ssh':
|
pdb = pMysqlDb()
|
||||||
return setSlaveStatusSSH(version)
|
dlist = pdb.query('show slave status')
|
||||||
if mode == 'sync-user':
|
|
||||||
return setSlaveStatusSyncUser(version)
|
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSyncUser(version=''):
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
if len(dlist) == 0:
|
||||||
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
return mw.returnJson(False, '需要手动添加同步账户或者执行初始化!')
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
for v in dlist:
|
||||||
db.query('stop slave')
|
connection_name = ''
|
||||||
else:
|
cmd = "slave"
|
||||||
ip = dlist[0]['Master_Host']
|
if 'Channel_Name' in v:
|
||||||
conn = pSqliteDb('slave_sync_user')
|
ch_name = v['Channel_Name']
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
cmd = "slave for channel '{}'".format(ch_name)
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
user = data['user']
|
|
||||||
apass = data['pass']
|
|
||||||
|
|
||||||
db.query("start slave")
|
if (v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes'):
|
||||||
# db.query("start slave user='{}' password='{}';".format(user, apass))
|
pdb.query("stop {}".format(cmd))
|
||||||
|
else:
|
||||||
return mw.returnJson(True, '设置成功!')
|
pdb.query("start {}".format(cmd))
|
||||||
|
|
||||||
|
|
||||||
def setSlaveStatusSSH(version=''):
|
|
||||||
|
|
||||||
db = pMysqlDb()
|
|
||||||
dlist = db.query('show slave status')
|
|
||||||
if len(dlist) == 0:
|
|
||||||
return mw.returnJson(False, '需要手动添加主服务命令或者执行初始化!')
|
|
||||||
|
|
||||||
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
|
|
||||||
db.query('stop slave')
|
|
||||||
else:
|
|
||||||
ip = dlist[0]['Master_Host']
|
|
||||||
conn = pSqliteDb('slave_id_rsa')
|
|
||||||
data = conn.field('ip,ps').where("ip=?", (ip,)).find()
|
|
||||||
if len(data) == 0:
|
|
||||||
return mw.returnJson(False, '没有数据无法重启!')
|
|
||||||
u = data['ps'].split("|")
|
|
||||||
db.query("start slave user='{}' password='{}';".format(u[0], u[1]))
|
|
||||||
|
|
||||||
return mw.returnJson(True, '设置成功!')
|
return mw.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
|
||||||
def deleteSlave(version=''):
|
def deleteSlave(version=''):
|
||||||
|
args = getArgs()
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
dlist = db.query('stop slave')
|
if 'sign' in args:
|
||||||
dlist = db.query('reset slave all')
|
sign = args['sign']
|
||||||
|
db.query("stop slave for channel '{}'".format(sign))
|
||||||
|
db.query("reset slave all for channel '{}'".format(sign))
|
||||||
|
else:
|
||||||
|
db.query('stop slave')
|
||||||
|
db.query('reset slave all')
|
||||||
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
return mw.returnJson(True, '删除成功!')
|
||||||
|
|
||||||
|
|
||||||
@@ -2628,11 +2635,13 @@ def dumpMysqlData(version=''):
|
|||||||
|
|
||||||
############### --- 重要 同步---- ###########
|
############### --- 重要 同步---- ###########
|
||||||
|
|
||||||
|
def asyncTmpfile():
|
||||||
|
path = '/tmp/mysql_async_status.txt'
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def writeDbSyncStatus(data):
|
def writeDbSyncStatus(data):
|
||||||
path = '/tmp/db_async_status.txt'
|
path = asyncTmpfile()
|
||||||
# status_data['code'] = 1
|
|
||||||
# status_data['msg'] = '主服务器备份完成...'
|
|
||||||
# status_data['progress'] = 30
|
|
||||||
mw.writeFile(path, json.dumps(data))
|
mw.writeFile(path, json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
@@ -2650,16 +2659,22 @@ def doFullSync(version=''):
|
|||||||
|
|
||||||
def doFullSyncUser(version=''):
|
def doFullSyncUser(version=''):
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
sync_db = args['db']
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
conn = pSqliteDb('slave_sync_user')
|
conn = pSqliteDb('slave_sync_user')
|
||||||
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
if sync_sign != '':
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = conn.field('ip,port,user,pass,mode,cmd').find()
|
||||||
|
|
||||||
user = data['user']
|
user = data['user']
|
||||||
apass = data['pass']
|
apass = data['pass']
|
||||||
port = data['port']
|
port = data['port']
|
||||||
@@ -2696,21 +2711,30 @@ def doFullSyncUser(version=''):
|
|||||||
db.query("start slave")
|
db.query("start slave")
|
||||||
|
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
os.system("rm -rf " + bak_file)
|
|
||||||
|
if os.path.exists(bak_file):
|
||||||
|
os.system("rm -rf " + bak_file)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def doFullSyncSSH(version=''):
|
def doFullSyncSSH(version=''):
|
||||||
|
|
||||||
args = getArgs()
|
args = getArgs()
|
||||||
data = checkArgs(args, ['db'])
|
data = checkArgs(args, ['db', 'sign'])
|
||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
|
sync_db = args['db']
|
||||||
|
sync_sign = args['sign']
|
||||||
|
|
||||||
db = pMysqlDb()
|
db = pMysqlDb()
|
||||||
|
|
||||||
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
id_rsa_conn = pSqliteDb('slave_id_rsa')
|
||||||
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
if sync_sign != '':
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').where(
|
||||||
|
'ip=?', (sync_sign,)).find()
|
||||||
|
else:
|
||||||
|
data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
|
||||||
|
|
||||||
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
|
||||||
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
id_rsa = data['id_rsa'].replace('\\n', '\n')
|
||||||
@@ -2752,7 +2776,8 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
|
||||||
|
|
||||||
dbname = args['db']
|
dbname = args['db']
|
||||||
cmd = "cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
cmd = "cd /www/server/mdserver-web && source bin/activate && python3 " + \
|
||||||
|
getSPluginDir() + "/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
|
||||||
print(cmd)
|
print(cmd)
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
@@ -2775,7 +2800,10 @@ def doFullSyncSSH(version=''):
|
|||||||
if copy_status == None:
|
if copy_status == None:
|
||||||
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
|
||||||
|
|
||||||
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
|
cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \
|
||||||
|
getSPluginDir() + \
|
||||||
|
'/index.py get_master_rep_slave_user_cmd {"username":"' + \
|
||||||
|
db_user + '","db":""}'
|
||||||
stdin, stdout, stderr = ssh.exec_command(cmd)
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
||||||
result = stdout.read()
|
result = stdout.read()
|
||||||
result = result.decode('utf-8')
|
result = result.decode('utf-8')
|
||||||
@@ -2817,8 +2845,9 @@ def doFullSyncSSH(version=''):
|
|||||||
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
db.query("start slave user='{}' password='{}';".format(
|
# "start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password'])
|
||||||
uinfo['username'], uinfo['password']))
|
|
||||||
|
db.query("start slave")
|
||||||
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
|
||||||
|
|
||||||
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
os.system("rm -rf " + SSH_PRIVATE_KEY)
|
||||||
@@ -2832,12 +2861,16 @@ def fullSync(version=''):
|
|||||||
if not data[0]:
|
if not data[0]:
|
||||||
return data[1]
|
return data[1]
|
||||||
|
|
||||||
status_file = '/tmp/db_async_status.txt'
|
sign = ''
|
||||||
|
if 'sign' in args:
|
||||||
|
sign = args['sign']
|
||||||
|
|
||||||
|
status_file = asyncTmpfile()
|
||||||
if args['begin'] == '1':
|
if args['begin'] == '1':
|
||||||
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + getPluginDir() + \
|
||||||
getPluginDir() + \
|
'/index.py do_full_sync {"db":"' + \
|
||||||
'/index.py do_full_sync {"db":"' + args['db'] + '"} &'
|
args['db'] + '","sign":"' + sign + '"} &'
|
||||||
print(cmd)
|
# print(cmd)
|
||||||
mw.execShell(cmd)
|
mw.execShell(cmd)
|
||||||
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
||||||
|
|
||||||
|
|||||||
+164
-80
@@ -162,34 +162,6 @@ function myPort(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//数据库存储信置
|
|
||||||
function changeMySQLDataPath(act) {
|
|
||||||
if (act != undefined) {
|
|
||||||
layer.confirm(lan.soft.mysql_to_msg, { closeBtn: 2, icon: 3 }, function() {
|
|
||||||
var datadir = $("#datadir").val();
|
|
||||||
var data = 'datadir=' + datadir;
|
|
||||||
var loadT = layer.msg(lan.soft.mysql_to_msg1, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
|
||||||
$.post('/database?action=SetDataDir', data, function(rdata) {
|
|
||||||
layer.close(loadT)
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/database?action=GetMySQLInfo', '', function(rdata) {
|
|
||||||
var LimitCon = '<p class="conf_p">\
|
|
||||||
<input id="datadir" class="phpUploadLimit bt-input-text mr5" style="width:350px;" type="text" value="' + rdata.datadir + '" name="datadir">\
|
|
||||||
<span onclick="changePath(\'datadir\')" class="glyphicon glyphicon-folder-open cursor mr20" style="width:auto"></span><button class="btn btn-success btn-sm" onclick="changeMySQLDataPath(1)">' + lan.soft.mysql_to + '</button>\
|
|
||||||
</p>';
|
|
||||||
$(".soft-man-con").html(LimitCon);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//数据库配置状态
|
//数据库配置状态
|
||||||
function myPerfOpt() {
|
function myPerfOpt() {
|
||||||
//获取MySQL配置
|
//获取MySQL配置
|
||||||
@@ -1691,12 +1663,12 @@ function getMasterRepSlaveListPage(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deleteSlave(){
|
function deleteSlave(sign){
|
||||||
myPost('delete_slave', {}, function(data){
|
myPost('delete_slave', {sign:sign}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
showMsg(rdata['msg'], function(){
|
showMsg(rdata['msg'], function(){
|
||||||
masterOrSlaveConf();
|
masterOrSlaveConf();
|
||||||
},{},3000);
|
},{icon:rdata.status?1:2,time:3000},3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1704,28 +1676,73 @@ function deleteSlave(){
|
|||||||
function getFullSyncStatus(db){
|
function getFullSyncStatus(db){
|
||||||
var timeId = null;
|
var timeId = null;
|
||||||
|
|
||||||
var btn = '<div class="table_toolbar" style="left:0px;"><span data-status="init" class="sync btn btn-default btn-sm" id="begin_full_sync" title="">开始</span></div>';
|
myPost('get_slave_list', {page:1,page_size:100}, function(data){
|
||||||
var loadOpen = layer.open({
|
var rdata = $.parseJSON(data.data);
|
||||||
type: 1,
|
var rsource = rdata.data;
|
||||||
title: '全量同步['+db+']',
|
|
||||||
area: '500px',
|
if (db == 'ALL' && rsource.length>1){
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
layer.msg("多主不支持该模式!",{icon:2});
|
||||||
<div class='divtable mtb10'>\
|
return;
|
||||||
<span id='full_msg'></span>\
|
|
||||||
<div class='progress'>\
|
|
||||||
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
"+btn+"\
|
|
||||||
</div>",
|
|
||||||
cancel: function(){
|
|
||||||
clearInterval(timeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dataSource = '';
|
||||||
|
if (rsource.length>1){
|
||||||
|
var sourceList = '';
|
||||||
|
for (var i = 0; i < rsource.length; i++) {
|
||||||
|
if ('Channel_Name' in rsource[i]){
|
||||||
|
sourceList += '<option val="'+rsource[i]['Master_Host']+'">'+rsource[i]['Master_Host']+'</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource = "<p class='line' style='text-align:center;'>\
|
||||||
|
<span>同步数据源:</span>\
|
||||||
|
<select class='bt-input-text' name='data_source' style='width:200px;'>" + sourceList + "</select>\
|
||||||
|
</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: '全量同步['+db+']',
|
||||||
|
area: '500px',
|
||||||
|
content:"<div class='bt-form pd15'>\
|
||||||
|
<div class='divtable mtb10'>\
|
||||||
|
"+dataSource+"\
|
||||||
|
<span id='full_msg'></span>\
|
||||||
|
<div class='progress'>\
|
||||||
|
<div class='progress-bar' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' style='min-width: 2em;'>0%</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class='table_toolbar' style='left:0px;'>\
|
||||||
|
<span data-status='init' class='sync btn btn-default btn-sm' id='begin_full_sync'>开始</span>\
|
||||||
|
</div>\
|
||||||
|
</div>",
|
||||||
|
cancel: function(){
|
||||||
|
clearInterval(timeId);
|
||||||
|
},
|
||||||
|
success:function(){
|
||||||
|
$('#begin_full_sync').click(function(){
|
||||||
|
var val = $(this).data('status');
|
||||||
|
var sign = '';
|
||||||
|
if (dataSource !=''){
|
||||||
|
sign = $('select[name="data_source"]').val();
|
||||||
|
}
|
||||||
|
if (val == 'init'){
|
||||||
|
fullSync(db, sign, 1);
|
||||||
|
timeId = setInterval(function(){
|
||||||
|
fullSync(db,sign,0);
|
||||||
|
}, 1000);
|
||||||
|
$(this).data('status','starting');
|
||||||
|
} else {
|
||||||
|
layer.msg("正在同步中..",{icon:0});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function fullSync(db,begin){
|
function fullSync(db,sign,begin){
|
||||||
|
|
||||||
myPostN('full_sync', {db:db,begin:begin}, function(data){
|
myPostN('full_sync', {db:db,sign:sign,begin:begin}, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
$('#full_msg').text(rdata['msg']);
|
$('#full_msg').text(rdata['msg']);
|
||||||
$('.progress-bar').css('width',rdata['progress']+'%');
|
$('.progress-bar').css('width',rdata['progress']+'%');
|
||||||
@@ -1738,19 +1755,6 @@ function getFullSyncStatus(db){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#begin_full_sync').click(function(){
|
|
||||||
var val = $(this).attr('data-status');
|
|
||||||
if (val == 'init'){
|
|
||||||
fullSync(db,1);
|
|
||||||
timeId = setInterval(function(){
|
|
||||||
fullSync(db,0);
|
|
||||||
}, 1000);
|
|
||||||
$(this).attr('data-status','starting');
|
|
||||||
} else {
|
|
||||||
layer.msg("正在同步中..");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSlaveSSH(ip=''){
|
function addSlaveSSH(ip=''){
|
||||||
@@ -1920,18 +1924,29 @@ function addSlaveSyncUser(ip=''){
|
|||||||
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
|
||||||
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
|
||||||
<div class='line'>\
|
<div class='line'>\
|
||||||
<span class='tname'>CMD[最好填好]</span>\
|
<span class='tname'>CMD[必须填写]</span>\
|
||||||
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<input type='hidden' name='mode' value='"+mode+"' />\
|
<input type='hidden' name='mode' value='"+mode+"' />\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
$('textarea[name="cmd"]').html(cmd);
|
$('textarea[name="cmd"]').html(cmd);
|
||||||
|
|
||||||
$('textarea[name="cmd"]').change(function(){
|
$('textarea[name="cmd"]').change(function(){
|
||||||
var val = $(this).val();
|
var val = $(this).val();
|
||||||
var vlist = val.split(',');
|
|
||||||
var a = {};
|
var a = {};
|
||||||
|
if (val.toLowerCase().indexOf('for')>0){
|
||||||
|
cmd_tmp = val.split('for');
|
||||||
|
val = cmd_tmp[0].trim();
|
||||||
|
|
||||||
|
const channel_str = cmd_tmp[1].trim();
|
||||||
|
const ch_reg = /channel \'(.*)\';/;
|
||||||
|
var match_val = channel_str.match(ch_reg);
|
||||||
|
if (match_val.length>1){
|
||||||
|
a['channel'] = match_val[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlist = val.split(',');
|
||||||
for (var i in vlist) {
|
for (var i in vlist) {
|
||||||
var tmp = toTrim(vlist[i]);
|
var tmp = toTrim(vlist[i]);
|
||||||
var tmp_a = tmp.split(" ");
|
var tmp_a = tmp.split(" ");
|
||||||
@@ -2098,7 +2113,7 @@ function getSlaveUserList(){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步账户列表',
|
title: '同步账户列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2122,7 +2137,7 @@ function getSlaveSSHList(page=1){
|
|||||||
layerId = layer.open({
|
layerId = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: 'SSH列表',
|
title: 'SSH列表',
|
||||||
area: '500px',
|
area: '600px',
|
||||||
content:"<div class='bt-form pd20 c6'>\
|
content:"<div class='bt-form pd20 c6'>\
|
||||||
<div class='divtable mtb10'>\
|
<div class='divtable mtb10'>\
|
||||||
<div><table class='table table-hover get-slave-ssh-list'>\
|
<div><table class='table table-hover get-slave-ssh-list'>\
|
||||||
@@ -2230,10 +2245,16 @@ function masterOrSlaveConf(version=''){
|
|||||||
myPost('get_slave_list', _data, function(data){
|
myPost('get_slave_list', _data, function(data){
|
||||||
var rdata = $.parseJSON(data.data);
|
var rdata = $.parseJSON(data.data);
|
||||||
var list = '';
|
var list = '';
|
||||||
|
|
||||||
|
var isHasSign = false;
|
||||||
for(i in rdata.data){
|
for(i in rdata.data){
|
||||||
|
|
||||||
var v = rdata.data[i];
|
var v = rdata.data[i];
|
||||||
var status = "<a class='btlink db_error'>异常</>";
|
if ('Channel_Name' in v){
|
||||||
|
isHasSign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = "<a data-id="+i+" class='btlink db_error'>异常</>";
|
||||||
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
|
||||||
status = "正常";
|
status = "正常";
|
||||||
}
|
}
|
||||||
@@ -2245,13 +2266,23 @@ function masterOrSlaveConf(version=''){
|
|||||||
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
list += '<td>' + rdata.data[i]['Master_Log_File'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_IO_Running'] +'</td>';
|
||||||
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
list += '<td>' + rdata.data[i]['Slave_SQL_Running'] +'</td>';
|
||||||
|
|
||||||
|
if (isHasSign){
|
||||||
|
list += '<td>' + v['Channel_Name'] +'</td>';
|
||||||
|
}
|
||||||
|
|
||||||
list += '<td>' + status +'</td>';
|
list += '<td>' + status +'</td>';
|
||||||
list += '<td style="text-align:right">' +
|
list += '<td style="text-align:right">' +
|
||||||
'<a href="javascript:;" class="btlink" onclick="deleteSlave()" title="删除">删除</a>' +
|
'<a data-id="'+i+'" href="javascript:;" class="btlink btn_delete_slave" title="删除">删除</a>' +
|
||||||
'</td>';
|
'</td>';
|
||||||
list += '</tr>';
|
list += '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var signThead_th = '';
|
||||||
|
if (isHasSign){
|
||||||
|
var signThead_th = '<th>标识</th>';
|
||||||
|
}
|
||||||
|
|
||||||
var con = '<div class="divtable mtb10">\
|
var con = '<div class="divtable mtb10">\
|
||||||
<div class="tablescroll">\
|
<div class="tablescroll">\
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||||
@@ -2262,6 +2293,7 @@ function masterOrSlaveConf(version=''){
|
|||||||
<th>日志</th>\
|
<th>日志</th>\
|
||||||
<th>IO</th>\
|
<th>IO</th>\
|
||||||
<th>SQL</th>\
|
<th>SQL</th>\
|
||||||
|
'+signThead_th+'\
|
||||||
<th>状态</th>\
|
<th>状态</th>\
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
<th style="text-align:right;">操作</th></tr></thead>\
|
||||||
<tbody>\
|
<tbody>\
|
||||||
@@ -2276,22 +2308,74 @@ function masterOrSlaveConf(version=''){
|
|||||||
// </div>
|
// </div>
|
||||||
$(".table_slave_status_list").html(con);
|
$(".table_slave_status_list").html(con);
|
||||||
|
|
||||||
$('.db_error').click(function(){
|
$(".btn_delete_slave").click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var v = rdata.data[id];
|
||||||
|
if ('Channel_Name' in v){
|
||||||
|
deleteSlave(v['Channel_Name']);
|
||||||
|
} else{
|
||||||
|
deleteSlave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.db_error').click(function(){
|
||||||
|
var id = $(this).data('id');
|
||||||
|
var info = rdata.data[id];
|
||||||
|
|
||||||
|
var err_line = "";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>IO错误</td>\
|
||||||
|
<td>"+ (info['Last_IO_Error'] == '' ? '无':info['Last_IO_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>SQL错误</td>\
|
||||||
|
<td>"+(info['Last_SQL_Error'] == '' ? '无':info['Last_SQL_Error'])+"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
|
err_line +="<tr>\
|
||||||
|
<td>状态</td>\
|
||||||
|
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
|
||||||
|
</tr>";
|
||||||
|
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '同步异常信息',
|
title: '同步异常信息',
|
||||||
area: '500px',
|
area: ['600px','300px'],
|
||||||
content:"<form class='bt-form pd20 pb70'>\
|
btn:['复制错误',"取消"],
|
||||||
<div class='line'>"+v['Error']+"</div>\
|
content:"<form class='bt-form pd15'>\
|
||||||
<div class='bt-form-submit-btn'>\
|
<div class='divtable mtb10'>\
|
||||||
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
|
<div class='tablescroll'>\
|
||||||
|
<table class='table table-hover' width='100%' cellspacing='0' cellpadding='0' border='0' style='border: 0 none;'>\
|
||||||
|
<thead><tr>\
|
||||||
|
<th style='width:80px;'>类型</th>\
|
||||||
|
<th>内容</th>\
|
||||||
|
</tr></thead>\
|
||||||
|
<tbody>"+ err_line +"</tbody>\
|
||||||
|
</table>\
|
||||||
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</form>",
|
</form>",
|
||||||
success:function(){
|
success:function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
$('.class-copy-db-err').click(function(){
|
// $('.class-copy-db-err').click(function(){
|
||||||
copyText(v['Error']);
|
// copyText(v['Error']);
|
||||||
});
|
// });
|
||||||
|
},
|
||||||
|
yes:function(){
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
|||||||
# https://t.me/gjgzs2022 | 22/m
|
# https://t.me/gjgzs2022 | 22/m
|
||||||
# 高价收量 👑 集团收量 ❤️ 流量变现/支付宝代付 ❤️ 微信代付/实名认证/过人脸🕵️♀️各种账号处理✅ | 28/m
|
# 高价收量 👑 集团收量 ❤️ 流量变现/支付宝代付 ❤️ 微信代付/实名认证/过人脸🕵️♀️各种账号处理✅ | 28/m
|
||||||
# https://zhaoziyuan.la/ | web | 15/m | 2m | next,7/15
|
# https://zhaoziyuan.la/ | web | 15/m | 2m | next,7/15
|
||||||
# 香港高防CDN |9/m
|
# 腾云机场 |9/m
|
||||||
# mvirtua | web | 7/m
|
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
@@ -53,7 +52,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="香港高防CDN、免实名、试用30天", url='https://www.100dun.com')
|
text="🚀腾云机场|解锁流媒体和ChatGPT", url='https://www.tencloud.net/#/register?code=OGvXSTsc')
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
|||||||
# https://t.me/gjgzs2022 | 22/m
|
# https://t.me/gjgzs2022 | 22/m
|
||||||
# 高价收量 👑 集团收量 ❤️ 流量变现/支付宝代付 ❤️ 微信代付/实名认证/过人脸🕵️♀️各种账号处理✅ | 28/m
|
# 高价收量 👑 集团收量 ❤️ 流量变现/支付宝代付 ❤️ 微信代付/实名认证/过人脸🕵️♀️各种账号处理✅ | 28/m
|
||||||
# https://zhaoziyuan.la/ | web | 15/m | 2m | next,9/15
|
# https://zhaoziyuan.la/ | web | 15/m | 2m | next,9/15
|
||||||
# 香港高防CDN |9/m
|
# 腾云机场 |9/m
|
||||||
# mvirtua | web | 7/m
|
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
@@ -62,7 +61,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="香港高防CDN、免实名、试用30天", url='https://www.100dun.com')
|
text="🚀腾云机场|解锁流媒体和ChatGPT", url='https://www.tencloud.net/#/register?code=OGvXSTsc')
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
|
|||||||
Reference in New Issue
Block a user