diff --git a/plugins/mariadb/index.py b/plugins/mariadb/index.py
index ffaac21b8..135a41c1c 100755
--- a/plugins/mariadb/index.py
+++ b/plugins/mariadb/index.py
@@ -2137,8 +2137,6 @@ def getSlaveList(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
-
- # print(dlist)
ret = []
for x in range(0, len(dlist)):
tmp = {}
@@ -2148,6 +2146,24 @@ def getSlaveList(version=''):
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'] = ret
diff --git a/plugins/mysql-apt/conf/mysql.sql b/plugins/mysql-apt/conf/mysql.sql
index f6df3e957..8262a9ec2 100755
--- a/plugins/mysql-apt/conf/mysql.sql
+++ b/plugins/mysql-apt/conf/mysql.sql
@@ -40,4 +40,17 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`addtime` TEXT
);
+-- 从库配置主库的[user]
+-- drop table `slave_user`;
+CREATE TABLE IF NOT EXISTS `slave_sync_user` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `ip` TEXT,
+ `port` TEXT,
+ `user` TEXT,
+ `pass` TEXT,
+ `mode` TEXT,
+ `cmd` TEXT,
+ `addtime` TEXT
+);
+
diff --git a/plugins/mysql-apt/index.html b/plugins/mysql-apt/index.html
index 0b689695b..f6a6f8892 100755
--- a/plugins/mysql-apt/index.html
+++ b/plugins/mysql-apt/index.html
@@ -13,6 +13,7 @@
diff --git a/plugins/mysql-apt/index.py b/plugins/mysql-apt/index.py
index 7ab236ade..e6bf94de9 100755
--- a/plugins/mysql-apt/index.py
+++ b/plugins/mysql-apt/index.py
@@ -1954,6 +1954,123 @@ def getSlaveSSHList(version=''):
return mw.getJson(data)
+def getSlaveSyncUserByIp(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['ip'])
+ if not data[0]:
+ return data[1]
+
+ ip = args['ip']
+
+ conn = pSqliteDb('slave_sync_user')
+ data = conn.field('ip,port,user,pass,mode,cmd').where(
+ "ip=?", (ip,)).select()
+ return mw.returnJson(True, 'ok', data)
+
+
+def addSlaveSyncUser(version=''):
+ import base64
+
+ args = getArgs()
+ data = checkArgs(args, ['ip'])
+ if not data[0]:
+ return data[1]
+
+ ip = args['ip']
+ if ip == "":
+ return mw.returnJson(True, 'ok')
+
+ data = checkArgs(args, ['port', 'user', 'pass', 'mode'])
+ if not data[0]:
+ return data[1]
+
+ cmd = args['cmd']
+ port = args['port']
+ user = args['user']
+ apass = args['pass']
+ mode = args['mode']
+ addTime = time.strftime('%Y-%m-%d %X', time.localtime())
+
+ conn = pSqliteDb('slave_sync_user')
+ data = conn.field('ip').where("ip=?", (ip,)).select()
+ if len(data) > 0:
+ res = conn.where("ip=?", (ip,)).save(
+ 'port,user,pass,mode,cmd', (port, user, apass, mode, cmd))
+ else:
+ conn.add('ip,port,user,cmd,user,pass,mode,addtime',
+ (ip, port, user, cmd, user, apass, mode, addTime))
+
+ return mw.returnJson(True, '设置成功!')
+
+
+def delSlaveSyncUser(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['ip'])
+ if not data[0]:
+ return data[1]
+
+ ip = args['ip']
+
+ conn = pSqliteDb('slave_sync_user')
+ conn.where("ip=?", (ip,)).delete()
+ return mw.returnJson(True, '删除成功!')
+
+
+def getSlaveSyncUserList(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['page', 'page_size'])
+ if not data[0]:
+ return data[1]
+
+ page = int(args['page'])
+ page_size = int(args['page_size'])
+
+ conn = pSqliteDb('slave_sync_user')
+ limit = str((page - 1) * page_size) + ',' + str(page_size)
+
+ field = 'id,ip,port,user,pass,cmd,addtime'
+ clist = conn.field(field).limit(limit).order('id desc').select()
+ count = conn.count()
+
+ data = {}
+ _page = {}
+ _page['count'] = count
+ _page['p'] = page
+ _page['row'] = page_size
+ _page['tojs'] = args['tojs']
+ data['page'] = mw.getPage(_page)
+ data['data'] = clist
+
+ return mw.getJson(data)
+
+
+def getSyncModeFile():
+ return getServerDir() + "/sync.mode"
+
+
+def getSlaveSyncMode(version):
+ sync_mode = getSyncModeFile()
+ if os.path.exists(sync_mode):
+ mode = mw.readFile(sync_mode).strip()
+ return mw.returnJson(True, 'ok', mode)
+ return mw.returnJson(False, 'fail')
+
+
+def setSlaveSyncMode(version):
+ args = getArgs()
+ data = checkArgs(args, ['mode'])
+ if not data[0]:
+ return data[1]
+ mode = args['mode']
+ sync_mode = getSyncModeFile()
+
+ if mode == 'none':
+ os.remove(sync_mode)
+ else:
+ mw.writeFile(sync_mode, mode)
+ return mw.returnJson(True, '设置成功', mode)
+
+
def getSlaveSSHByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
@@ -2040,6 +2157,24 @@ def getSlaveList(version=''):
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'] = ret
@@ -2056,6 +2191,47 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
+ mode_file = getSyncModeFile()
+ if not os.path.exists(mode_file):
+ return mw.returnJson(False, '需要先设置同步配置')
+
+ mode = mw.readFile(mode_file)
+ if mode == 'ssh':
+ return initSlaveStatusSSH(version)
+ if mode == 'sync-user':
+ return initSlaveStatusSyncUser(version)
+
+
+def initSlaveStatusSyncUser(version=''):
+ conn = pSqliteDb('slave_sync_user')
+ data = conn.field('ip,port,user,pass,mode,cmd').find()
+ if len(data) < 1:
+ return mw.returnJson(False, '需要先添加同步用户配置!')
+
+ # print(data)
+ db = pMysqlDb()
+ dlist = db.query('show slave status')
+ if len(dlist) > 0:
+ return mw.returnJson(False, '已经初始化好了zz...')
+
+ u = data
+
+ mode_name = 'classic'
+ if u['mode'] == '1':
+ mode_name = 'gtid'
+
+ local_mode = recognizeDbMode()
+ if local_mode != mode_name:
+ return mw.returnJson(False, '同步模式不一致!')
+
+ t = db.query(u['cmd'])
+ # print(t)
+ db.query("start slave user='{}' password='{}';".format(
+ u['user'], u['pass']))
+ return mw.returnJson(True, '初始化成功!')
+
+
+def initSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) > 0:
@@ -2124,6 +2300,41 @@ def initSlaveStatus(version=''):
def setSlaveStatus(version=''):
+ mode_file = getSyncModeFile()
+ if not os.path.exists(mode_file):
+ return mw.returnJson(False, '需要先设置同步配置')
+
+ mode = mw.readFile(mode_file)
+ if mode == 'ssh':
+ return setSlaveStatusSSH(version)
+ if mode == 'sync-user':
+ return setSlaveStatusSyncUser(version)
+
+
+def setSlaveStatusSyncUser(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_sync_user')
+ data = conn.field('ip,port,user,pass,mode,cmd').find()
+ if len(data) == 0:
+ return mw.returnJson(False, '没有数据无法重启!')
+ user = data['user']
+ apass = data['pass']
+
+ db.query("start slave")
+ # db.query("start slave user='{}' password='{}';".format(user, apass))
+
+ return mw.returnJson(True, '设置成功!')
+
+
+def setSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
@@ -2192,6 +2403,68 @@ def writeDbSyncStatus(data):
def doFullSync(version=''):
+ mode_file = getSyncModeFile()
+ if not os.path.exists(mode_file):
+ return mw.returnJson(False, '需要先设置同步配置')
+
+ mode = mw.readFile(mode_file)
+ if mode == 'ssh':
+ return doFullSyncSSH(version)
+ if mode == 'sync-user':
+ return doFullSyncUser(version)
+
+
+def doFullSyncUser(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['db'])
+ if not data[0]:
+ return data[1]
+
+ sync_db = args['db']
+
+ db = pMysqlDb()
+
+ conn = pSqliteDb('slave_sync_user')
+ data = conn.field('ip,port,user,pass,mode,cmd').find()
+ user = data['user']
+ apass = data['pass']
+ port = data['port']
+ ip = data['ip']
+
+ bak_file = '/tmp/tmp.sql'
+
+ writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
+ dmp_option = ''
+ mode = recognizeDbMode()
+ if mode == 'gtid':
+ dmp_option = ' --set-gtid-purged=off '
+
+ writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
+
+ if not os.path.exists(bak_file):
+ dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
+ port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
+ mw.execShell(dump_sql_data)
+
+ writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
+ if os.path.exists(bak_file):
+ pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
+ sock = getSocketFile()
+ my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
+ ' ' + sync_db + ' < ' + bak_file
+ mw.execShell(my_import_cmd)
+
+ if version == '8.0':
+ db.query("start slave user='{}' password='{}';".format(user, apass))
+ else:
+ db.query("start slave")
+
+ writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
+ os.system("rm -rf " + bak_file)
+ return True
+
+
+def doFullSyncSSH(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
@@ -2523,6 +2796,18 @@ if __name__ == "__main__":
print(delSlaveSSH(version))
elif func == 'update_slave_ssh':
print(updateSlaveSSH(version))
+ elif func == 'get_slave_sync_user_list':
+ print(getSlaveSyncUserList(version))
+ elif func == 'get_slave_sync_user_by_ip':
+ print(getSlaveSyncUserByIp(version))
+ elif func == 'add_slave_sync_user':
+ print(addSlaveSyncUser(version))
+ elif func == 'del_slave_sync_user':
+ print(delSlaveSyncUser(version))
+ elif func == 'get_slave_sync_mode':
+ print(getSlaveSyncMode(version))
+ elif func == 'set_slave_sync_mode':
+ print(setSlaveSyncMode(version))
elif func == 'init_slave_status':
print(initSlaveStatus(version))
elif func == 'set_slave_status':
diff --git a/plugins/mysql-apt/js/mysql-apt.js b/plugins/mysql-apt/js/mysql-apt.js
index c7dce8538..ba8930bc9 100755
--- a/plugins/mysql-apt/js/mysql-apt.js
+++ b/plugins/mysql-apt/js/mysql-apt.js
@@ -1545,13 +1545,9 @@ function getMasterRepSlaveUserCmd(username, db=''){
function delMasterRepSlaveUser(username){
myPost('del_master_rep_slave_user', {username:username}, function(data){
var rdata = $.parseJSON(data.data);
- layer.msg(rdata.msg);
-
- $('.layui-layer-close1').click();
-
- setTimeout(function(){
+ showMsg(rdata.msg, function(){
getMasterRepSlaveList();
- },1000);
+ },{icon: rdata.status ? 1 : 2},1000)
});
}
@@ -1821,8 +1817,23 @@ function addSlaveSSH(ip=''){
function delSlaveSSH(ip){
myPost('del_slave_ssh', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
- layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
- getSlaveSSHPage();
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getSlaveSSHPage();
+ }
+ },{icon: rdata.status ? 1 : 2}, 600);
+ });
+}
+
+
+function delSlaveSyncUser(ip){
+ myPost('del_slave_sync_user', {ip:ip}, function(rdata){
+ var rdata = $.parseJSON(rdata.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getSlaveSyncUserPage();
+ }
+ },{icon: rdata.status ? 1 : 2}, 600);
});
}
@@ -1872,6 +1883,237 @@ function getSlaveSSHPage(page=1){
}
+
+function addSlaveSyncUser(ip=''){
+
+ myPost('get_slave_sync_user_by_ip', {ip:ip}, function(rdata){
+
+ var rdata = $.parseJSON(rdata.data);
+
+ var ip = '127.0.0.1';
+ var port = "22";
+ var cmd = '';
+ var user = 'input_sync_user';
+ var pass = 'input_sync_pwd';
+ var mode = '0';
+
+ if (rdata.data.length>0){
+ ip = rdata.data[0]['ip'];
+ port = rdata.data[0]['port'];
+ cmd = rdata.data[0]['cmd'];
+ user = rdata.data[0]['user'];
+ pass = rdata.data[0]['pass'];
+ mode = rdata.data[0]['mode'];
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: ['500px','470px'],
+ title: '同步账户',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["确认","取消"],
+ content: "
",
+ success:function(){
+ $('textarea[name="cmd"]').html(cmd);
+
+ $('textarea[name="cmd"]').change(function(){
+ var val = $(this).val();
+ var vlist = val.split(',');
+ var a = {};
+ for (var i in vlist) {
+ var tmp = toTrim(vlist[i]);
+ var tmp_a = tmp.split(" ");
+ var real_tmp = tmp_a[tmp_a.length-1];
+ var kv = real_tmp.split("=");
+ a[kv[0]] = kv[1].replace("'",'').replace("'",'');
+ }
+
+ $('input[name="ip"]').val(a['MASTER_HOST']);
+ $('input[name="port"]').val(a['MASTER_PORT']);
+ $('input[name="user"]').val(a['MASTER_USER']);
+ $('input[name="pass"]').val(a['MASTER_PASSWORD']);
+
+ console.log(a['MASTER_AUTO_POSITION'],typeof(a['MASTER_AUTO_POSITION']));
+ if (typeof(a['MASTER_AUTO_POSITION']) != 'undefined' ){
+ $('input[name="mode"]').val('1');
+ }
+ });
+ },
+ yes:function(index){
+ var ip = $('input[name="ip"]').val();
+ var port = $('input[name="port"]').val();
+ var user = $('input[name="user"]').val();
+ var pass = $('input[name="pass"]').val();
+ var cmd = $('textarea[name="cmd"]').val();
+ var mode = $('input[name="mode"]').val();
+
+ var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
+ myPost('add_slave_sync_user', data, function(ret_data){
+ layer.close(index);
+ var rdata = $.parseJSON(ret_data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getSlaveSyncUserPage();
+ }
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ }
+ });
+ });
+}
+
+function getSlaveSyncUserPage(page=1){
+ var _data = {};
+ _data['page'] = page;
+ _data['page_size'] = 5;
+ _data['tojs'] ='getSlaveSyncUserPage';
+ myPost('get_slave_sync_user_list', _data, function(data){
+ var layerId = null;
+ var rdata = [];
+ try {
+ rdata = $.parseJSON(data.data);
+ } catch(e) {
+ console.log(e);
+ }
+
+ var list = '';
+ var user_list = rdata['data'];
+ for (i in user_list) {
+ var ip = user_list[i]['ip'];
+ var port = user_list[i]['port'];
+ var user = user_list[i]['user'];
+ var apass = user_list[i]['pass'];
+
+ var cmd = '未设置';
+ if (user_list[i]['cmd']!=''){
+ cmd = '已设置';
+ }
+
+ list += '
'+ip+' | \
+ '+port+' | \
+ '+user+' | \
+ '+apass+' | \
+ '+cmd+' | \
+ \
+ 修改 | \
+ 删除\
+ | \
+
';
+ }
+
+ $('.get-slave-ssh-list tbody').html(list);
+ $('.dataTables_paginate_4').html(rdata['page']);
+ });
+}
+
+function getSlaveCfg(){
+
+ myPost('get_slave_sync_mode', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ var mode_none = 'success';
+ var mode_ssh = 'danger';
+ var mode_sync_user = 'danger';
+ if(rdata.status){
+ var mode_none = 'danger';
+ if (rdata.data == 'ssh'){
+ var mode_ssh = 'success';
+ var mode_sync_user = 'danger';
+ } else {
+ var mode_ssh = 'danger';
+ var mode_sync_user = 'success';
+ }
+ }
+
+ layerId = layer.open({
+ type: 1,
+ title: '同步配置',
+ area: ['400px','180px'],
+ content:"
",
+ success:function(){
+ $('.btn-slave-ssh').click(function(){
+ getSlaveSSHList();
+ });
+
+ $('.btn-slave-user').click(function(){
+ getSlaveUserList();
+ });
+
+ $('.slave-db-mode').click(function(){
+ var _this = this;
+ var mode = 'none';
+ if ($(this).hasClass('btn-ssh')){
+ mode = 'ssh';
+ }
+ if ($(this).hasClass('btn-sync-user')){
+ mode = 'sync-user';
+ }
+
+ myPost('set_slave_sync_mode', {mode:mode}, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ $('.slave-db-mode').remove('btn-success').addClass('btn-danger');
+ $(_this).removeClass('btn-danger').addClass('btn-success');
+ },{icon:rdata.status?1:2},2000);
+ });
+
+ });
+ }
+ });
+ });
+}
+
+
+function getSlaveUserList(){
+
+ var page = '
';
+ page += '
添加同步账户
';
+
+ layerId = layer.open({
+ type: 1,
+ title: '同步账户列表',
+ area: '500px',
+ content:"
",
+ success:function(){
+ getSlaveSyncUserPage(1);
+ }
+ });
+}
+
function getSlaveSSHList(page=1){
var page = '
';
@@ -1991,7 +2233,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
- var status = "异常";
+ var status = "
异常>";
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
status = "正常";
}
@@ -2033,6 +2275,26 @@ function masterOrSlaveConf(version=''){
// 添加\
//
$(".table_slave_status_list").html(con);
+
+ $('.db_error').click(function(){
+ layer.open({
+ type: 1,
+ title: '同步异常信息',
+ area: '500px',
+ content:"