diff --git a/plugins/mysql-yum/conf/my5.7.cnf b/plugins/mysql-yum/conf/my5.7.cnf index 7cb48bbb0..7358357e8 100644 --- a/plugins/mysql-yum/conf/my5.7.cnf +++ b/plugins/mysql-yum/conf/my5.7.cnf @@ -72,6 +72,9 @@ replicate-ignore-db = performance_schema replicate-ignore-db = mysql replicate-ignore-db = test +master_info_repository = table +relay_log_info_repository = table + default_storage_engine = InnoDB innodb_data_home_dir = {$SERVER_APP_PATH}/data innodb_data_file_path = ibdata1:10M:autoextend diff --git a/plugins/mysql-yum/conf/my8.0.cnf b/plugins/mysql-yum/conf/my8.0.cnf index bf08e38fb..3fb46bebe 100644 --- a/plugins/mysql-yum/conf/my8.0.cnf +++ b/plugins/mysql-yum/conf/my8.0.cnf @@ -68,6 +68,9 @@ replicate-ignore-db = performance_schema replicate-ignore-db = mysql replicate-ignore-db = test +master_info_repository = table +relay_log_info_repository = table + default_storage_engine = InnoDB innodb_data_home_dir = {$SERVER_APP_PATH}/data innodb_data_file_path = ibdata1:10M:autoextend diff --git a/plugins/mysql-yum/index.py b/plugins/mysql-yum/index.py index aaad23593..5d5b06935 100755 --- a/plugins/mysql-yum/index.py +++ b/plugins/mysql-yum/index.py @@ -101,6 +101,14 @@ def getDbPort(): 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(): file = getConf() content = mw.readFile(file) @@ -1863,27 +1871,34 @@ def getMasterRepSlaveUserCmd(version): mode = recognizeDbMode() + sid = getDbServerId() + channel_name = "" + if sid != '': + channel_name = " for channel 'r{}';".format(sid) + if mode == "gtid": sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \ 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': sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \ clist[0]['username'] + "', SOURCE_PASSWORD='" + \ - clist[0]['password'] + "', MASTER_AUTO_POSITION=1" + clist[0]['password'] + \ + "', MASTER_AUTO_POSITION=1" + channel_name else: sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \ clist[0]['username'] + "', MASTER_PASSWORD='" + \ clist[0]['password'] + \ "', 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": sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \ clist[0]['username'] + "', SOURCE_PASSWORD='" + \ clist[0]['password'] + \ "', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \ - "',SOURCE_LOG_POS=" + str(mstatus[0]["Position"]) + "',SOURCE_LOG_POS=" + \ + str(mstatus[0]["Position"]) + channel_name data = {} data['cmd'] = sql @@ -2154,22 +2169,10 @@ def updateSlaveSSH(version=''): def getSlaveList(version=''): - db = pMysqlDb() 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'] = ret - + data['data'] = dlist return mw.getJson(data) @@ -2193,100 +2196,149 @@ def initSlaveStatus(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=''): conn = pSqliteDb('slave_sync_user') - data = conn.field('ip,port,user,pass,mode,cmd').find() - if len(data) < 1: + slave_data = conn.field('ip,port,user,pass,mode,cmd').select() + if len(slave_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...') + pdb = pMysqlDb() + if len(slave_data) == 1: + dlist = pdb.query('show slave status') + if len(dlist) > 0: + return mw.returnJson(False, '已经初始化好了zz...') - u = data + msg = '' + local_mode = recognizeDbMode() + for x in range(len(slave_data)): + slave_t = slave_data[x] + mode_name = 'classic' + base_t = 'IP:' + slave_t['ip'] + ",PORT:" + \ + slave_t['port'] + ",USER:" + slave_t['user'] - mode_name = 'classic' - if u['mode'] == '1': - mode_name = 'gtid' + if slave_t['mode'] == '1': + mode_name = 'gtid' - local_mode = recognizeDbMode() - if local_mode != mode_name: - return mw.returnJson(False, '同步模式不一致!') + if local_mode != mode_name: + msg += base_t + '->同步模式不一致' + continue - t = db.query(u['cmd']) - # print(t) - db.query("start slave user='{}' password='{}';".format( - u['user'], u['pass'])) - return mw.returnJson(True, '初始化成功!') + 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=''): db = pMysqlDb() dlist = db.query('show slave status') - if len(dlist) > 0: - return mw.returnJson(False, '已经初始化好了zz...') 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配置】!') - 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')) + local_mode = recognizeDbMode() import paramiko paramiko.util.log_to_file('paramiko.log') 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) - 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) - - cmd = 'cd /www/server/mdserver-web && python3 plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}' - stdin, stdout, stderr = ssh.exec_command(cmd) - result = stdout.read() - result = result.decode('utf-8') - cmd_data = json.loads(result) - - if not cmd_data['status']: - return mw.returnJson(False, '[主]:' + cmd_data['msg']) - - local_mode = recognizeDbMode() - if local_mode != cmd_data['data']['mode']: - return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode)) - - u = cmd_data['data']['info'] - ps = u['username'] + "|" + u['password'] - conn.where('ip=?', (ip,)).setField('ps', ps) - db.query('stop slave') - - # 保证同步IP一致 - cmd = cmd_data['data']['cmd'] - if cmd.find('SOURCE_HOST') > -1: - cmd = re.sub(r"SOURCE_HOST='(.*)'", - "SOURCE_HOST='" + ip + "'", cmd, 1) - - if cmd.find('MASTER_HOST') > -1: - cmd = re.sub(r"MASTER_HOST='(.*)'", - "MASTER_HOST='" + ip + "'", cmd, 1) - db.query(cmd) - db.query("start slave user='{}' password='{}';".format( - u['username'], u['password'])) - except Exception as e: - return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e)) - - ssh.close() - time.sleep(1) - os.system("rm -rf " + SSH_PRIVATE_KEY) + try: + 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'] + 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":""}' + 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) + if not cmd_data['status']: + return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg']) + + if local_mode != cmd_data['data']['mode']: + return mw.returnJson(False, '[主][' + ip + ']:【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode)) + + u = cmd_data['data']['info'] + + ps = u['username'] + "|" + u['password'] + print(ps) + conn.where('ip=?', (ip,)).setField('ps', ps) + db.query('stop slave') + + # 保证同步IP一致 + cmd = cmd_data['data']['cmd'] + if cmd.find('SOURCE_HOST') > -1: + cmd = re.sub(r"SOURCE_HOST='(.*?)'", + "SOURCE_HOST='" + ip + "'", cmd, 1) + + if cmd.find('MASTER_HOST') > -1: + cmd = re.sub(r"MASTER_HOST='(.*?)'", + "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, '初始化成功!') @@ -2296,60 +2348,37 @@ def setSlaveStatus(version=''): 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') + pdb = pMysqlDb() + dlist = pdb.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'] + for v in dlist: + connection_name = '' + cmd = "slave" + if 'Channel_Name' in v: + ch_name = v['Channel_Name'] + cmd = "slave for channel '{}'".format(ch_name) - db.query("start slave") - # db.query("start slave user='{}' password='{}';".format(user, apass)) + if (v["Slave_IO_Running"] == 'Yes' or v["Slave_SQL_Running"] == 'Yes'): + pdb.query("stop {}".format(cmd)) + else: + pdb.query("start {}".format(cmd)) return mw.returnJson(True, '设置成功!') -def setSlaveStatusSSH(version=''): - +def deleteSlave(version=''): + args = getArgs() 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') + if 'sign' in args: + sign = args['sign'] + db.query("stop slave for channel '{}'".format(sign)) + db.query("reset slave all for channel '{}'".format(sign)) 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, '设置成功!') - + db.query('stop slave') + db.query('reset slave all') -def deleteSlave(version=''): - db = pMysqlDb() - dlist = db.query('stop slave') - dlist = db.query('reset slave all') return mw.returnJson(True, '删除成功!') @@ -2385,11 +2414,13 @@ def dumpMysqlData(version=''): ############### --- 重要 同步---- ########### +def asyncTmpfile(): + path = '/tmp/mysql_yum_async_status.txt' + return path + + def writeDbSyncStatus(data): - path = '/tmp/db_async_status.txt' - # status_data['code'] = 1 - # status_data['msg'] = '主服务器备份完成...' - # status_data['progress'] = 30 + path = asyncTmpfile() mw.writeFile(path, json.dumps(data)) @@ -2407,16 +2438,22 @@ def doFullSync(version=''): def doFullSyncUser(version=''): args = getArgs() - data = checkArgs(args, ['db']) + data = checkArgs(args, ['db', 'sign']) if not data[0]: return data[1] sync_db = args['db'] + sync_sign = args['sign'] db = pMysqlDb() 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'] apass = data['pass'] port = data['port'] @@ -2433,9 +2470,10 @@ def doFullSyncUser(version=''): 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 + \ - " --ssl-mode=DISABLED " + sync_db + " > " + bak_file + dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \ + port + " -u" + user + " -p\"" + apass + \ + "\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file + # print(dump_sql_data) mw.execShell(dump_sql_data) writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40}) @@ -2452,21 +2490,30 @@ def doFullSyncUser(version=''): db.query("start slave") 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 def doFullSyncSSH(version=''): args = getArgs() - data = checkArgs(args, ['db']) + data = checkArgs(args, ['db', 'sign']) if not data[0]: return data[1] + sync_db = args['db'] + sync_sign = args['sign'] + db = pMysqlDb() 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" id_rsa = data['id_rsa'].replace('\\n', '\n') @@ -2508,7 +2555,8 @@ def doFullSyncSSH(version=''): writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5}) 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 " + \ + getPluginDir() + "/index.py dump_mysql_data {\"db\":'" + dbname + "'}" print(cmd) stdin, stdout, stderr = ssh.exec_command(cmd) result = stdout.read() @@ -2531,7 +2579,10 @@ def doFullSyncSSH(version=''): if copy_status == None: 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 ' + \ + getPluginDir() + \ + '/index.py get_master_rep_slave_user_cmd {"username":"' + \ + db_user + '","db":""}' stdin, stdout, stderr = ssh.exec_command(cmd) result = stdout.read() result = result.decode('utf-8') @@ -2543,10 +2594,12 @@ def doFullSyncSSH(version=''): cmd = cmd_data['data']['cmd'] # 保证同步IP一致 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: - 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) uinfo = cmd_data['data']['info'] @@ -2560,6 +2613,8 @@ def doFullSyncSSH(version=''): mw.execShell("cd /tmp && gzip -d dump.sql.gz") cmd = root_dir + "/bin/mysql -S " + msock + \ " -uroot -p" + pwd + " < /tmp/dump.sql" + + print(cmd) import_data = mw.execShell(cmd) if import_data[0] == '': print(import_data[1]) @@ -2569,8 +2624,9 @@ def doFullSyncSSH(version=''): writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100}) return 'fail' - db.query("start slave user='{}' password='{}';".format( - uinfo['username'], uinfo['password'])) + # "start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password']) + + db.query("start slave") writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100}) os.system("rm -rf " + SSH_PRIVATE_KEY) @@ -2584,12 +2640,16 @@ def fullSync(version=''): if not data[0]: 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': - cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \ - getPluginDir() + \ - '/index.py do_full_sync {"db":"' + args['db'] + '"} &' - print(cmd) + 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}) diff --git a/plugins/mysql-yum/js/mysql-yum.js b/plugins/mysql-yum/js/mysql-yum.js index 2903e45f4..218c147f5 100755 --- a/plugins/mysql-yum/js/mysql-yum.js +++ b/plugins/mysql-yum/js/mysql-yum.js @@ -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 = '

\ - \ - \ -

'; - $(".soft-man-con").html(LimitCon); - }); -} - - - - //数据库配置状态 function myPerfOpt() { //获取MySQL配置 @@ -1691,12 +1663,12 @@ function getMasterRepSlaveListPage(){ } -function deleteSlave(){ - myPost('delete_slave', {}, function(data){ +function deleteSlave(sign){ + myPost('delete_slave', {sign:sign}, function(data){ var rdata = $.parseJSON(data.data); showMsg(rdata['msg'], function(){ masterOrSlaveConf(); - },{},3000); + },{icon:rdata.status?1:2,time:3000},3000); }); } @@ -1704,28 +1676,70 @@ function deleteSlave(){ function getFullSyncStatus(db){ var timeId = null; - var btn = '
开始
'; - var loadOpen = layer.open({ - type: 1, - title: '全量同步['+db+']', - area: '500px', - content:"
\ -
\ - \ -
\ -
0%
\ -
\ -
\ - "+btn+"\ -
", - cancel: function(){ - clearInterval(timeId); + myPost('get_slave_list', {page:1,page_size:100}, function(data){ + var rdata = $.parseJSON(data.data); + var rsource = rdata.data; + + if (db == 'ALL' && rsource.length>1){ + layer.msg("多主不支持该模式!",{icon:2}); + return; + } + + var dataSource = ''; + if (rsource.length>1){ + var sourceList = ''; + for (var i = 0; i < rsource.length; i++) { + if ('Channel_Name' in rsource[i]){ + sourceList += ''; + } + } + + dataSource = "

\ + 同步数据源:\ + \ +

"; } + + layer.open({ + type: 1, + title: '全量同步['+db+']', + area: '500px', + content:"
\ +
\ + "+dataSource+"\ + \ +
\ +
0%
\ +
\ +
\ +
\ + 开始\ +
\ +
", + cancel: function(){ + clearInterval(timeId); + }, + success:function(){ + $('#begin_full_sync').click(function(){ + var val = $(this).data('status'); + var 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); $('#full_msg').text(rdata['msg']); $('.progress-bar').css('width',rdata['progress']+'%'); @@ -1920,18 +1934,29 @@ function addSlaveSyncUser(ip=''){
同步账户
\
同步密码
\
\ - CMD[最好填好]\ + CMD[必须填写]\
\
\ \ ", success:function(){ $('textarea[name="cmd"]').html(cmd); - $('textarea[name="cmd"]').change(function(){ var val = $(this).val(); - var vlist = val.split(','); 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) { var tmp = toTrim(vlist[i]); var tmp_a = tmp.split(" "); @@ -2098,7 +2123,7 @@ function getSlaveUserList(){ layerId = layer.open({ type: 1, title: '同步账户列表', - area: '500px', + area: '600px', content:"
\
\
\ @@ -2122,7 +2147,7 @@ function getSlaveSSHList(page=1){ layerId = layer.open({ type: 1, title: 'SSH列表', - area: '500px', + area: '600px', content:"
\
\
\ @@ -2230,10 +2255,16 @@ function masterOrSlaveConf(version=''){ myPost('get_slave_list', _data, function(data){ var rdata = $.parseJSON(data.data); var list = ''; + + var isHasSign = false; for(i in rdata.data){ var v = rdata.data[i]; - var status = "异常"; + if ('Channel_Name' in v){ + isHasSign = true; + } + + var status = "异常"; if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){ status = "正常"; } @@ -2245,13 +2276,23 @@ function masterOrSlaveConf(version=''){ list += ''; list += ''; list += ''; + + if (isHasSign){ + list += ''; + } + list += ''; list += ''; list += ''; } + var signThead_th = ''; + if (isHasSign){ + var signThead_th = ''; + } + var con = '
\
\
' + rdata.data[i]['Master_Log_File'] +'' + rdata.data[i]['Slave_IO_Running'] +'' + rdata.data[i]['Slave_SQL_Running'] +'' + v['Channel_Name'] +'' + status +'' + - '删除' + + '删除' + '
标识
\ @@ -2262,6 +2303,7 @@ function masterOrSlaveConf(version=''){ \ \ \ + '+signThead_th+'\ \ \ \ @@ -2276,22 +2318,74 @@ function masterOrSlaveConf(version=''){ // $(".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 +="\ + \ + \ + "; + err_line +="\ + \ + \ + "; + + err_line +="\ + \ + \ + "; + layer.open({ type: 1, title: '同步异常信息', - area: '500px', - content:"
\ -
"+v['Error']+"
\ -
\ - \ + area: ['600px','300px'], + btn:['复制错误',"取消"], + content:"\ +
\ +
\ +
日志IOSQL状态操作
IO错误"+ (info['Last_IO_Error'] == '' ? '无':info['Last_IO_Error'])+"
SQL错误"+(info['Last_SQL_Error'] == '' ? '无':info['Last_SQL_Error'])+"
状态"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"
\ + \ + \ + \ + \ + "+ err_line +"\ +
类型内容
\ +
\
\ - ", + ", success:function(){ - copyText(v['Error']); - $('.class-copy-db-err').click(function(){ - copyText(v['Error']); - }); + // copyText(v['Error']); + // $('.class-copy-db-err').click(function(){ + // 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; + } } }); }); diff --git a/plugins/mysql/index.py b/plugins/mysql/index.py index 08d914228..57da3e096 100755 --- a/plugins/mysql/index.py +++ b/plugins/mysql/index.py @@ -2477,7 +2477,7 @@ def initSlaveStatusSyncUser(version=''): # u['user'], u['pass'])) pdb.query("start slave") - pdb.query("start all slaves ") + pdb.query("start all slaves") if msg == '': msg = '初始化成功!' @@ -2514,7 +2514,11 @@ def initSlaveStatusSSH(version=''): 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'] + cmd = 'cd /www/server/mdserver-web && source bin/activate && python3 ' + \ + getPluginDir() + \ + '/index.py get_master_rep_slave_user_cmd {"username":"' + \ + db_user + '","db":""}' stdin, stdout, stderr = ssh.exec_command(cmd) result = stdout.read() result = result.decode('utf-8') @@ -2768,7 +2772,8 @@ def doFullSyncSSH(version=''): writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5}) 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 " + \ + getPluginDir() + "/index.py dump_mysql_data {\"db\":'" + dbname + "'}" print(cmd) stdin, stdout, stderr = ssh.exec_command(cmd) result = stdout.read() @@ -2791,7 +2796,10 @@ def doFullSyncSSH(version=''): if copy_status == None: 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 ' + \ + getPluginDir() + \ + '/index.py get_master_rep_slave_user_cmd {"username":"' + \ + db_user + '","db":""}' stdin, stdout, stderr = ssh.exec_command(cmd) result = stdout.read() result = result.decode('utf-8') diff --git a/plugins/mysql/js/mysql.js b/plugins/mysql/js/mysql.js index edd29123b..2463cbfe4 100755 --- a/plugins/mysql/js/mysql.js +++ b/plugins/mysql/js/mysql.js @@ -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 = '

\ - \ - \ -

'; - $(".soft-man-con").html(LimitCon); - }); -} - - - - //数据库配置状态 function myPerfOpt() { //获取MySQL配置