diff --git a/plugins/mysql/conf/mysql.sql b/plugins/mysql/conf/mysql.sql
index 6413b9e40..38b822738 100755
--- a/plugins/mysql/conf/mysql.sql
+++ b/plugins/mysql/conf/mysql.sql
@@ -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
+);
+
+
diff --git a/plugins/mysql/index.py b/plugins/mysql/index.py
index ee2d29c6d..9d864a86c 100755
--- a/plugins/mysql/index.py
+++ b/plugins/mysql/index.py
@@ -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')
diff --git a/plugins/mysql/js/mysql.js b/plugins/mysql/js/mysql.js
index f49af1faf..9e9046181 100755
--- a/plugins/mysql/js/mysql.js
+++ b/plugins/mysql/js/mysql.js
@@ -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: "
",
+ });
+
+ // \
+ //
访问权限\
+ //
\
+ // \
+ //
\
+ //
\
+
+ $("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("");
+ } 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:"",
+ });
+
+ 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 += ''+name+' | \
+ '+user_list[i]['password']+' | \
+ '+user_list[i]['accept']+' | \
+ \
+ 修改 | \
+ 删除 | \
+ 从库同步命令\
+ | \
+
';
+ }
+
+ var page = '';
+ page += '添加同步账户
';
+
+
+
+ var loadOpen = layer.open({
+ type: 1,
+ title: '同步账户列表',
+ area: '500px',
+ content:""
+ });
+
+ $('.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 += '';
list += '' + rdata.data[i]['name'] +' | ';
- list += '' + rdata.data[i]['username'] +' | ';
- list += '' +
- '***' +
- ''+
- ''+
- ' | ';
+ list += '' + (rdata.data[i]['master']?'是':'否') +' | ';
list += '' +
- '权限 | ' +
- '改密 | ' +
- '删除' +
- ' | ';
+ ''+(rdata.data[i]['master']?'退出':'加入')+'' +
+ '';
list += '
';
}
@@ -1141,14 +1313,16 @@ function masterOrSlaveConf(version){
\
\
数据库名 | \
- 用户名 | \
- 密码 | \
+ 同步 | \
操作 |
\
\
'+ list +'\
\
\
- \
+ \
+ \
+ 同步账户列表\
+
\
';
$(".table_master_list").html(con);