mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-18 23:45:52 +08:00
up
This commit is contained in:
@@ -15,3 +15,14 @@ CREATE TABLE IF NOT EXISTS `databases` (
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `master_replication_user` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`accept` TEXT,
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -41,8 +41,31 @@ def getInitDFile():
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def is_number(s):
|
||||
try:
|
||||
float(s)
|
||||
return True
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import unicodedata
|
||||
unicodedata.numeric(s)
|
||||
return True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
|
||||
# print(args)
|
||||
|
||||
# if is_number(args):
|
||||
# args = sys.argv[3:]
|
||||
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
@@ -1126,6 +1149,94 @@ def getTotalStatistics():
|
||||
return mw.returnJson(False, 'fail', data)
|
||||
|
||||
|
||||
def findBinlogDoDb():
|
||||
conf = getConf()
|
||||
con = mw.readFile(conf)
|
||||
rep = 'binlog-do-db\s*=\s*(.*)'
|
||||
tmp = re.search(rep, con)
|
||||
dlist = tmp.groups()[0].strip()
|
||||
return dlist.split(',')
|
||||
|
||||
|
||||
def getMasterDbList(version=''):
|
||||
args = getArgs()
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
data = {}
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
conn = pSqliteDb('databases')
|
||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
||||
condition = ''
|
||||
dodb = findBinlogDoDb()
|
||||
data['dodb'] = dodb
|
||||
|
||||
if not search == '':
|
||||
condition = "name like '%" + search + "%'"
|
||||
field = 'id,pid,name,username,password,accept,ps,addtime'
|
||||
clist = conn.where(condition, ()).field(
|
||||
field).limit(limit).order('id desc').select()
|
||||
count = conn.where(condition, ()).count()
|
||||
|
||||
for x in xrange(0, len(clist)):
|
||||
if clist[x]['name'] in dodb:
|
||||
clist[x]['master'] = 1
|
||||
else:
|
||||
clist[x]['master'] = 0
|
||||
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = 'dbList'
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def setDbMaster(version):
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
conf = getConf()
|
||||
con = mw.readFile(conf)
|
||||
rep = 'binlog-do-db\s*=\s*(.*)'
|
||||
tmp = re.search(rep, con)
|
||||
dlist = tmp.groups()[0].strip()
|
||||
dodb = dlist.split(',')
|
||||
|
||||
if not args['name'] in dodb:
|
||||
dlist = dlist + ',' + args['name']
|
||||
rep = "binlog-do-db\s*=\s*(.*)"
|
||||
con = re.sub(rep, 'binlog-do-db=' + dlist, con)
|
||||
mw.writeFile(conf, con)
|
||||
|
||||
else:
|
||||
new_dodb_str = ''
|
||||
for x in dodb:
|
||||
if x != args['name']:
|
||||
new_dodb_str = x + ','
|
||||
new_dodb_str_len = len(new_dodb_str)
|
||||
new_dodb_str = new_dodb_str[0:new_dodb_str_len - 1]
|
||||
rep = "binlog-do-db\s*=\s*(.*)"
|
||||
con = re.sub(rep, 'binlog-do-db=' + new_dodb_str, con)
|
||||
mw.writeFile(conf, con)
|
||||
|
||||
restart(version)
|
||||
return mw.returnJson(True, '设置成功', [args, dodb])
|
||||
|
||||
|
||||
def getMasterStatus(version=''):
|
||||
conf = getConf()
|
||||
con = mw.readFile(conf)
|
||||
@@ -1143,6 +1254,9 @@ def setMasterStatus(version=''):
|
||||
conf = getConf()
|
||||
con = mw.readFile(conf)
|
||||
|
||||
if con.find('#log-bin') != -1:
|
||||
return mw.returnJson(False, '必须开启二进制日志')
|
||||
|
||||
if con.find('#binlog-do-db') != -1:
|
||||
con = con.replace('#binlog-do-db', 'binlog-do-db')
|
||||
con = con.replace('#binlog-ignore-db', 'binlog-ignore-db')
|
||||
@@ -1154,6 +1268,132 @@ def setMasterStatus(version=''):
|
||||
mw.writeFile(conf, con)
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def getMasterRepSlaveList(version=''):
|
||||
args = getArgs()
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
data = {}
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
conn = pSqliteDb('master_replication_user')
|
||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
||||
condition = ''
|
||||
|
||||
if not search == '':
|
||||
condition = "name like '%" + search + "%'"
|
||||
field = 'id,username,password,accept,ps,addtime'
|
||||
clist = conn.where(condition, ()).field(
|
||||
field).limit(limit).order('id desc').select()
|
||||
count = conn.where(condition, ()).count()
|
||||
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = page
|
||||
_page['row'] = page_size
|
||||
_page['tojs'] = 'getMasterRepSlaveList'
|
||||
data['page'] = mw.getPage(_page)
|
||||
data['data'] = clist
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def addMasterRepSlaveUser(version=''):
|
||||
args = getArgs()
|
||||
data = checkArgs(args,
|
||||
['username', 'password'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
if not 'address' in args:
|
||||
address = ''
|
||||
else:
|
||||
address = args['address'].strip()
|
||||
|
||||
username = args['username'].strip()
|
||||
password = args['password'].strip()
|
||||
# ps = args['ps'].strip()
|
||||
# address = args['address'].strip()
|
||||
# dataAccess = args['dataAccess'].strip()
|
||||
|
||||
reg = "^[\w\.-]+$"
|
||||
if not re.match(reg, username):
|
||||
return mw.returnJson(False, '用户名不能带有特殊符号!')
|
||||
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
|
||||
if username in checks or len(username) < 1:
|
||||
return mw.returnJson(False, '用户名不合法!')
|
||||
if password in checks or len(password) < 1:
|
||||
return mw.returnJson(False, '密码不合法!')
|
||||
|
||||
if len(password) < 1:
|
||||
password = mw.md5(time.time())[0:8]
|
||||
|
||||
pdb = pMysqlDb()
|
||||
psdb = pSqliteDb('master_replication_user')
|
||||
|
||||
if psdb.where("username=?", (username)).count():
|
||||
return mw.returnJson(False, '用户已存在!')
|
||||
|
||||
result = pdb.execute("GRANT REPLICATION SLAVE ON *.* TO '" +
|
||||
username + "'@'%' identified by '" + password + "'")
|
||||
# print result
|
||||
isError = isSqlError(result)
|
||||
if isError != None:
|
||||
return isError
|
||||
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
psdb.add('username,password,accept,ps,addtime',
|
||||
(username, password, '%', '', addTime))
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
|
||||
def getMasterRepSlaveUserCmd(version):
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['username'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
psdb = pSqliteDb('master_replication_user')
|
||||
f = 'username,password'
|
||||
clist = psdb.field(f).where("username=?", (args['username'],)).limit(
|
||||
'1').order('id desc').select()
|
||||
# print(clist[0])
|
||||
|
||||
ip = mw.getLocalIp()
|
||||
port = getMyPort()
|
||||
|
||||
db = pMysqlDb()
|
||||
tmp = db.query('show master status')
|
||||
|
||||
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||
args['username'] + "', MASTER_PASSWORD='" + \
|
||||
clist[0]['password'] + \
|
||||
"', MASTER_LOG_FILE='" + tmp[0][0] + \
|
||||
"',MASTER_LOG_POS=" + str(tmp[0][1]) + ";"
|
||||
return mw.returnJson(True, '添加成功!', sql)
|
||||
|
||||
|
||||
def delMasterRepSlaveUser(version=''):
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['username'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
pdb = pMysqlDb()
|
||||
psdb = pSqliteDb('master_replication_user')
|
||||
pdb.execute("drop user '" + args['username'] + "'@'%'")
|
||||
psdb.where("username=?", (args['username'],)).delete()
|
||||
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
version = sys.argv[2]
|
||||
@@ -1227,9 +1467,21 @@ if __name__ == "__main__":
|
||||
print(alterTable())
|
||||
elif func == 'get_total_statistics':
|
||||
print(getTotalStatistics())
|
||||
elif func == 'get_masterdb_list':
|
||||
print(getMasterDbList(version))
|
||||
elif func == 'get_master_status':
|
||||
print(getMasterStatus(version))
|
||||
elif func == 'set_master_status':
|
||||
print(setMasterStatus(version))
|
||||
elif func == 'set_db_master':
|
||||
print(setDbMaster(version))
|
||||
elif func == 'get_master_rep_slave_list':
|
||||
print(getMasterRepSlaveList(version))
|
||||
elif func == 'add_master_rep_slave_user':
|
||||
print(addMasterRepSlaveUser(version))
|
||||
elif func == 'del_master_rep_slave_user':
|
||||
print(delMasterRepSlaveUser(version))
|
||||
elif func == 'get_master_rep_slave_user_cmd':
|
||||
print(getMasterRepSlaveUserCmd(version))
|
||||
else:
|
||||
print('error')
|
||||
|
||||
+189
-15
@@ -1102,7 +1102,186 @@ function repTools(db_name, res){
|
||||
}
|
||||
|
||||
|
||||
function masterOrSlaveConf(version){
|
||||
function setDbMaster(name){
|
||||
myPost('set_db_master', {name:name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
|
||||
setTimeout(function(){
|
||||
masterOrSlaveConf();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function addMasterRepSlaveUser(){
|
||||
|
||||
|
||||
var index = layer.open({
|
||||
type: 1,
|
||||
skin: 'demo-class',
|
||||
area: '500px',
|
||||
title: '添加同步账户',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: true,
|
||||
content: "<form class='bt-form pd20 pb70' id='add_master'>\
|
||||
<div class='line'><span class='tname'>用户名</span><div class='info-r'><input name='username' class='bt-input-text mr5' placeholder='用户名' type='text' style='width:330px;' value='"+(randomStrPwd(6))+"'></div></div>\
|
||||
<div class='line'>\
|
||||
<span class='tname'>密码</span>\
|
||||
<div class='info-r'><input class='bt-input-text mr5' type='text' name='password' id='MyPassword' style='width:330px' value='"+(randomStrPwd(16))+"' /><span title='随机密码' class='glyphicon glyphicon-repeat cursor' onclick='repeatPwd(16)'></span></div>\
|
||||
</div>\
|
||||
<input type='hidden' name='ps' value='' />\
|
||||
<div class='bt-form-submit-btn'>\
|
||||
<button id='my_mod_close' type='button' class='btn btn-danger btn-sm btn-title'>关闭</button>\
|
||||
<button type='button' class='btn btn-success btn-sm btn-title' id='submit_add_master' >提交</button>\
|
||||
</div>\
|
||||
</form>",
|
||||
});
|
||||
|
||||
// <div class='line'>\
|
||||
// <span class='tname'>访问权限</span>\
|
||||
// <div class='info-r '>\
|
||||
// <select class='bt-input-text mr5' name='dataAccess' style='width:100px'>\
|
||||
// <option value='127.0.0.1'>本地服务器</option>\
|
||||
// <option value=\"%\">所有人</option>\
|
||||
// <option value='ip'>指定IP</option>\
|
||||
// </select>\
|
||||
// </div>\
|
||||
// </div>\
|
||||
|
||||
$("input[name='name']").keyup(function(){
|
||||
var v = $(this).val();
|
||||
$("input[name='db_user']").val(v);
|
||||
$("input[name='ps']").val(v);
|
||||
});
|
||||
|
||||
$('#my_mod_close').click(function(){
|
||||
$('.layui-layer-close1').click();
|
||||
});
|
||||
$('select[name="dataAccess"]').change(function(){
|
||||
var v = $(this).val();
|
||||
if (v == 'ip'){
|
||||
$(this).after("<input id='dataAccess_subid' class='bt-input-text mr5' type='text' name='address' placeholder='多个IP使用逗号(,)分隔' style='width: 230px; display: inline-block;'>");
|
||||
} else {
|
||||
$('#dataAccess_subid').remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('#submit_add_master').click(function(){
|
||||
|
||||
var data = $("#add_master").serialize();
|
||||
data = decodeURIComponent(data);
|
||||
var dataObj = str2Obj(data);
|
||||
if(!dataObj['address']){
|
||||
dataObj['address'] = dataObj['dataAccess'];
|
||||
}
|
||||
// console.log(dataObj);
|
||||
myPost('add_master_rep_slave_user', dataObj, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
getMasterRepSlaveList();
|
||||
}
|
||||
$('.layui-layer-close1').click();
|
||||
},{icon: rdata.status ? 1 : 2},600);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getMasterRepSlaveUserCmd(username){
|
||||
myPost('get_master_rep_slave_user_cmd', {username:username}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '同步命令',
|
||||
area: '500px',
|
||||
content:"<form class='bt-form pd20 pb70' id='add_master'>\
|
||||
<div class='line'>"+rdata.data+"</div>\
|
||||
<div class='bt-form-submit-btn'>\
|
||||
<button type='button' class='btn btn-success btn-sm btn-title class-copy-cmd'>复制</button>\
|
||||
</div>\
|
||||
</form>",
|
||||
});
|
||||
|
||||
copyPass(rdata.data);
|
||||
$('.class-copy-cmd').click(function(){
|
||||
copyPass(rdata.data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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(){
|
||||
getMasterRepSlaveList();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
|
||||
function getMasterRepSlaveList(){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
myPost('get_master_rep_slave_list', _data, function(data){
|
||||
// console.log(data);
|
||||
var rdata = [];
|
||||
try {
|
||||
rdata = $.parseJSON(data.data);
|
||||
} catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
var list = '';
|
||||
// console.log(rdata['data']);
|
||||
var user_list = rdata['data'];
|
||||
for (i in user_list) {
|
||||
// console.log(i);
|
||||
var name = user_list[i]['username'];
|
||||
list += '<tr><td>'+name+'</td>\
|
||||
<td>'+user_list[i]['password']+'</td>\
|
||||
<td>'+user_list[i]['accept']+'</td>\
|
||||
<td>\
|
||||
<a class="btlink" target="_blank" href="'+'.'+'/'+name+'">修改</a> | \
|
||||
<a class="btlink" onclick="delMasterRepSlaveUser(\''+name+'\');">删除</a> | \
|
||||
<a class="btlink" onclick="getMasterRepSlaveUserCmd(\''+name+'\');">从库同步命令</a>\
|
||||
</td>\
|
||||
</tr>';
|
||||
}
|
||||
|
||||
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
|
||||
page += '<div class="table_toolbar"><span class="sync btn btn-default btn-sm" onclick="addMasterRepSlaveUser()" title="">添加同步账户</span></div>';
|
||||
|
||||
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '同步账户列表',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd20 c6'>\
|
||||
<div class='divtable mtb10'>\
|
||||
<div><table class='table table-hover'>\
|
||||
<thead><tr><th>用户民</th><th>密码</th><th>权限</th><th>操作</th></tr></thead>\
|
||||
<tbody>" + list + "</tbody>\
|
||||
</table></div>\
|
||||
"+page +"\
|
||||
</div>\
|
||||
</div>"
|
||||
});
|
||||
|
||||
$('.dataTables_paginate_4').html(rdata['page']);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function masterOrSlaveConf(version=''){
|
||||
|
||||
function getDbList(){
|
||||
var _data = {};
|
||||
@@ -1116,23 +1295,16 @@ function masterOrSlaveConf(version){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
myPost('get_db_list', _data, function(data){
|
||||
myPost('get_masterdb_list', _data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var list = '';
|
||||
for(i in rdata.data){
|
||||
list += '<tr>';
|
||||
list += '<td>' + rdata.data[i]['name'] +'</td>';
|
||||
list += '<td>' + rdata.data[i]['username'] +'</td>';
|
||||
list += '<td>' +
|
||||
'<span class="password" data-pw="'+rdata.data[i]['password']+'">***</span>' +
|
||||
'<span onclick="showHidePass(this)" class="glyphicon glyphicon-eye-open cursor pw-ico" style="margin-left:10px"></span>'+
|
||||
'<span class="ico-copy cursor btcopy" style="margin-left:10px" title="复制密码" onclick="copyPass(\''+rdata.data[i]['password']+'\')"></span>'+
|
||||
'</td>';
|
||||
list += '<td>' + (rdata.data[i]['master']?'是':'否') +'</td>';
|
||||
list += '<td style="text-align:right">' +
|
||||
'<a href="javascript:;" class="btlink" onclick="setDbAccess(\''+rdata.data[i]['username']+'\')" title="设置数据库权限">权限</a> | ' +
|
||||
'<a href="javascript:;" class="btlink" onclick="setDbPass('+rdata.data[i]['id']+',\''+ rdata.data[i]['username'] +'\',\'' + rdata.data[i]['password'] + '\')">改密</a> | ' +
|
||||
'<a href="javascript:;" class="btlink" onclick="delDb(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['name']+'\')" title="删除数据库">删除</a>' +
|
||||
'</td>';
|
||||
'<a href="javascript:;" class="btlink" onclick="setDbMaster(\''+rdata.data[i]['name']+'\')" title="设置数据库权限">'+(rdata.data[i]['master']?'退出':'加入')+'</a>' +
|
||||
'</td>';
|
||||
list += '</tr>';
|
||||
}
|
||||
|
||||
@@ -1141,14 +1313,16 @@ function masterOrSlaveConf(version){
|
||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||
<thead><tr>\
|
||||
<th>数据库名</th>\
|
||||
<th>用户名</th>\
|
||||
<th>密码</th>\
|
||||
<th>同步</th>\
|
||||
<th style="text-align:right;">操作</th></tr></thead>\
|
||||
<tbody>\
|
||||
'+ list +'\
|
||||
</tbody></table>\
|
||||
</div>\
|
||||
<div id="databasePage" class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
<div id="databasePage" class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
<div class="table_toolbar">\
|
||||
<span class="sync btn btn-default btn-sm" onclick="getMasterRepSlaveList()" title="">同步账户列表</span>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
$(".table_master_list").html(con);
|
||||
|
||||
Reference in New Issue
Block a user