pull/109/head
midoks 4 years ago
parent 85ddb26097
commit 002819e0ce
  1. 11
      plugins/mysql/conf/mysql.sql
  2. 252
      plugins/mysql/index.py
  3. 200
      plugins/mysql/js/mysql.js

@ -15,3 +15,14 @@ CREATE TABLE IF NOT EXISTS `databases` (
`ps` TEXT, `ps` TEXT,
`addtime` 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() 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(): def getArgs():
args = sys.argv[2:] args = sys.argv[2:]
# print(args)
# if is_number(args):
# args = sys.argv[3:]
tmp = {} tmp = {}
args_len = len(args) args_len = len(args)
@ -1126,6 +1149,94 @@ def getTotalStatistics():
return mw.returnJson(False, 'fail', data) 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=''): def getMasterStatus(version=''):
conf = getConf() conf = getConf()
con = mw.readFile(conf) con = mw.readFile(conf)
@ -1143,6 +1254,9 @@ def setMasterStatus(version=''):
conf = getConf() conf = getConf()
con = mw.readFile(conf) con = mw.readFile(conf)
if con.find('#log-bin') != -1:
return mw.returnJson(False, '必须开启二进制日志')
if con.find('#binlog-do-db') != -1: if con.find('#binlog-do-db') != -1:
con = con.replace('#binlog-do-db', 'binlog-do-db') con = con.replace('#binlog-do-db', 'binlog-do-db')
con = con.replace('#binlog-ignore-db', 'binlog-ignore-db') con = con.replace('#binlog-ignore-db', 'binlog-ignore-db')
@ -1154,6 +1268,132 @@ def setMasterStatus(version=''):
mw.writeFile(conf, con) mw.writeFile(conf, con)
return mw.returnJson(True, '设置成功') 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__": if __name__ == "__main__":
func = sys.argv[1] func = sys.argv[1]
version = sys.argv[2] version = sys.argv[2]
@ -1227,9 +1467,21 @@ if __name__ == "__main__":
print(alterTable()) print(alterTable())
elif func == 'get_total_statistics': elif func == 'get_total_statistics':
print(getTotalStatistics()) print(getTotalStatistics())
elif func == 'get_masterdb_list':
print(getMasterDbList(version))
elif func == 'get_master_status': elif func == 'get_master_status':
print(getMasterStatus(version)) print(getMasterStatus(version))
elif func == 'set_master_status': elif func == 'set_master_status':
print(setMasterStatus(version)) 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: else:
print('error') print('error')

@ -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(){ function getDbList(){
var _data = {}; var _data = {};
@ -1116,22 +1295,15 @@ function masterOrSlaveConf(version){
_data['search'] = search; _data['search'] = search;
} }
myPost('get_db_list', _data, function(data){ myPost('get_masterdb_list', _data, function(data){
var rdata = $.parseJSON(data.data); var rdata = $.parseJSON(data.data);
var list = ''; var list = '';
for(i in rdata.data){ for(i in rdata.data){
list += '<tr>'; list += '<tr>';
list += '<td>' + rdata.data[i]['name'] +'</td>'; list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td>' + rdata.data[i]['username'] +'</td>'; list += '<td>' + (rdata.data[i]['master']?'是':'否') +'</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 style="text-align:right">' + 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="setDbMaster(\''+rdata.data[i]['name']+'\')" title="设置数据库权限">'+(rdata.data[i]['master']?'退出':'加入')+'</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>'; '</td>';
list += '</tr>'; 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;">\ <table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\ <thead><tr>\
<th>数据库名</th>\ <th>数据库名</th>\
<th>用户名</th>\ <th>同步</th>\
<th>密码</th>\
<th style="text-align:right;">操作</th></tr></thead>\ <th style="text-align:right;">操作</th></tr></thead>\
<tbody>\ <tbody>\
'+ list +'\ '+ list +'\
</tbody></table>\ </tbody></table>\
</div>\ </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>'; </div>';
$(".table_master_list").html(con); $(".table_master_list").html(con);

Loading…
Cancel
Save