diff --git a/plugins/mariadb/conf/mariadb.sql b/plugins/mariadb/conf/mariadb.sql index f6df3e957..dc0089bfb 100755 --- a/plugins/mariadb/conf/mariadb.sql +++ b/plugins/mariadb/conf/mariadb.sql @@ -40,4 +40,18 @@ 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/mariadb/index.py b/plugins/mariadb/index.py index 2bfb93894..ffaac21b8 100755 --- a/plugins/mariadb/index.py +++ b/plugins/mariadb/index.py @@ -1943,6 +1943,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']) @@ -2047,6 +2164,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: @@ -2117,6 +2275,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') @@ -2185,6 +2378,65 @@ 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) + + 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']) @@ -2490,6 +2742,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/mariadb/js/mariadb.js b/plugins/mariadb/js/mariadb.js index 199484d0f..37444c929 100755 --- a/plugins/mariadb/js/mariadb.js +++ b/plugins/mariadb/js/mariadb.js @@ -1848,6 +1848,234 @@ 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: "
\ +
IP
\ +
端口
\ +
同步账户
\ +
同步密码
\ +
\ + CMD[最好填好]\ +
\ +
\ + \ +
", + 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:"
\ +
\ +
\ + \ + \ +
IPPORT同步账户同步密码CMD操作
\ + "+page +"\ +
\ +
", + success:function(){ + getSlaveSyncUserPage(1); + } + }); +} function getSlaveSSHList(page=1){ @@ -2087,7 +2315,7 @@ function masterOrSlaveConf(version=''){

\ Slave[从]配置\ \ - \ + \ \

\
\ diff --git a/plugins/mysql/js/mysql.js b/plugins/mysql/js/mysql.js index 5e20f5388..217351039 100755 --- a/plugins/mysql/js/mysql.js +++ b/plugins/mysql/js/mysql.js @@ -2020,7 +2020,6 @@ function getSlaveSyncUserPage(page=1){ function getSlaveCfg(){ - myPost('get_slave_sync_mode', '', function(data){ var rdata = $.parseJSON(data.data); var mode_none = 'success';