This commit is contained in:
midoks
2023-08-08 15:25:23 +08:00
parent 7024185b59
commit 98414db41d
6 changed files with 386 additions and 246 deletions
+207 -147
View File
@@ -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...')
u = data
mode_name = 'classic'
if u['mode'] == '1':
mode_name = 'gtid'
pdb = pMysqlDb()
if len(slave_data) == 1:
dlist = pdb.query('show slave status')
if len(dlist) > 0:
return mw.returnJson(False, '已经初始化好了zz...')
msg = ''
local_mode = recognizeDbMode()
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
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']
t = db.query(u['cmd'])
# print(t)
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
if slave_t['mode'] == '1':
mode_name = 'gtid'
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同步命令不合规范!')
# 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)
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)
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)
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 + ']:获取同步命令失败!')
if not cmd_data['status']:
return mw.returnJson(False, '[主]:' + cmd_data['msg'])
cmd_data = json.loads(result)
if not cmd_data['status']:
return mw.returnJson(False, '[主][' + ip + ']:' + cmd_data['msg'])
local_mode = recognizeDbMode()
if local_mode != cmd_data['data']['mode']:
return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
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']
conn.where('ip=?', (ip,)).setField('ps', ps)
db.query('stop slave')
u = cmd_data['data']['info']
# 保证同步IP一致
cmd = cmd_data['data']['cmd']
if cmd.find('SOURCE_HOST') > -1:
cmd = re.sub(r"SOURCE_HOST='(.*)'",
"SOURCE_HOST='" + ip + "'", cmd, 1)
ps = u['username'] + "|" + u['password']
print(ps)
conn.where('ip=?', (ip,)).setField('ps', ps)
db.query('stop slave')
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))
# 保证同步IP一致
cmd = cmd_data['data']['cmd']
if cmd.find('SOURCE_HOST') > -1:
cmd = re.sub(r"SOURCE_HOST='(.*?)'",
"SOURCE_HOST='" + ip + "'", cmd, 1)
ssh.close()
time.sleep(1)
os.system("rm -rf " + SSH_PRIVATE_KEY)
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))
return mw.returnJson(True, '设置成功!')
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]))
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 deleteSlave(version=''):
args = getArgs()
db = pMysqlDb()
dlist = db.query('stop slave')
dlist = db.query('reset slave all')
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:
db.query('stop slave')
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})