Compare commits

..
111 Commits
Author SHA1 Message Date
Mr Chen 869d7795a6 Merge pull request #321 from midoks/dev
0.12.1
2023-01-04 20:58:27 +08:00
midoks 0a3d976c6a 0.12.1
* mysql/mariadb/mysql-apt/mysql-yum增加新的同步方式[同步账户]。
* pureftp安装时自动放行端口。
* 面板ssl,添加【申请Lets证书】功能。
* 站点子域名绑定优化。
* 修复添加数据库名字判断。
* 增加PHP52的隐藏和显示指令。
* 各种细节优化。
2023-01-04 20:57:11 +08:00
midoks c4d39ef9fb Update intl.sh 2023-01-04 20:50:18 +08:00
midoks 8e5b499601 Update install.sh 2023-01-04 20:41:26 +08:00
midoks e6dff6094c Update tools.py 2023-01-04 20:21:52 +08:00
midoks 47dec45a27 Update tools.py 2023-01-04 20:20:47 +08:00
midoks 4706af7423 Update tools.py 2023-01-04 20:18:50 +08:00
midoks 1bc458eb8f 增加PHP52的隐藏和显示指令 2023-01-04 20:17:20 +08:00
midoks dc3f872592 Update config_api.py 2023-01-04 19:13:08 +08:00
midoks 3d48289329 up 2023-01-04 18:52:24 +08:00
midoks 6126539929 Update config_api.py 2023-01-04 18:00:49 +08:00
midoks cff5df6d13 Update requirements.txt 2023-01-04 17:57:55 +08:00
midoks 23a0b74f9d Update config.js 2023-01-04 17:49:58 +08:00
midoks 5927a3abab 面板ssl申请 2023-01-04 17:48:07 +08:00
midoks 4b176ad702 修复子目录绑定ssl申请问题 2023-01-03 23:45:51 +08:00
midoks 577103506d Update site_api.py 2023-01-03 23:39:40 +08:00
midoks 18f8d2b905 Update files.js 2023-01-03 18:56:56 +08:00
midoks 3a6b5339d2 Update config_api.py 2023-01-03 18:50:07 +08:00
midoks c25d4305f7 Update files.js 2023-01-03 18:49:58 +08:00
midoks b6ef87e97b up 2023-01-03 18:43:25 +08:00
midoks 4335668cd4 Update config_api.py 2023-01-03 18:29:20 +08:00
midoks 0fc2ab011d Update files.js 2023-01-03 18:26:20 +08:00
midoks 683035e6b7 up 2023-01-03 18:06:28 +08:00
midoks f2dfa7ad48 Update index.py 2023-01-03 14:55:39 +08:00
midoks 2ae2c188e7 Update index.py 2023-01-03 14:54:57 +08:00
midoks b5cd0564cb 安装,自动放行端口 2023-01-03 14:43:34 +08:00
midoks 2f274ce202 Update pure-ftpd.conf 2023-01-03 14:14:36 +08:00
midoks 0a67932473 域名添加重复bug优化 2023-01-02 22:56:19 +08:00
midoks 7b7cb215c4 Update config_api.py 2023-01-02 20:47:05 +08:00
midoks f6e98ae286 站点配置保持优化 2023-01-02 20:46:09 +08:00
midoks 5958f6e067 Update info.json 2023-01-02 12:01:05 +08:00
midoks 6dadfb1019 Update mysql.sql 2023-01-02 11:58:41 +08:00
midoks f5aeb5664b Update index.py 2023-01-02 11:58:08 +08:00
midoks ca1080937d Update index.py 2023-01-02 11:52:57 +08:00
midoks 1dd934ea3f mysql-yum加入主从同步 2023-01-02 11:47:35 +08:00
midoks a34512d057 Update ubuntu.sh 2023-01-02 01:06:54 +08:00
midoks 575c1e48ae Update info.json 2023-01-02 01:02:13 +08:00
midoks 9f3ee4997b up 2023-01-02 00:59:57 +08:00
midoks cfaa2d9f25 up 2023-01-02 00:30:44 +08:00
midoks aded1fc731 Update index.py 2023-01-02 00:16:12 +08:00
midoks 4a6e847743 Update index.py 2023-01-02 00:13:20 +08:00
midoks 24fac51538 Update index.py 2023-01-02 00:12:49 +08:00
midoks 148b32fed3 Update mariadb.js 2023-01-02 00:11:00 +08:00
midoks fff19d2c4a Update my.cnf 2023-01-02 00:04:43 +08:00
midoks a5e0332179 Update index.py 2023-01-01 23:42:14 +08:00
midoks 1349655570 up 2023-01-01 23:37:43 +08:00
midoks b9e617bf0f Update index.py 2023-01-01 21:58:26 +08:00
midoks f65d10e1e4 up 2023-01-01 21:56:45 +08:00
midoks 6d9ec087ce Update index.py 2023-01-01 21:18:55 +08:00
midoks bfb9da0471 up 2023-01-01 20:55:32 +08:00
midoks 8a95a68c81 Update update_dev.sh 2023-01-01 20:55:09 +08:00
midoks d9d81ded3d mysql-apt添加主从同步功能 2023-01-01 20:43:00 +08:00
midoks 403660c980 Update config_api.py 2023-01-01 20:26:36 +08:00
midoks ac06cfc83c mariadb添加新的同步方式 2023-01-01 20:22:06 +08:00
midoks c50012b9b5 Update index.py 2023-01-01 17:17:05 +08:00
midoks baeb0ddc8f up 2023-01-01 17:00:47 +08:00
midoks 83f8c99275 Update update.sh 2022-12-31 21:06:55 +08:00
midoks 2d2b454a31 Update update_dev.sh 2022-12-31 21:05:36 +08:00
midoks aad41ce14b Update index.py 2022-12-31 20:57:56 +08:00
midoks ebf8c82d33 导入优化 2022-12-31 20:30:02 +08:00
midoks d25100fec3 Update index.py 2022-12-31 20:01:20 +08:00
midoks fe658d9009 Update config_api.py 2022-12-31 17:10:58 +08:00
midoks f37c2c9bc6 Update index.py 2022-12-31 16:46:28 +08:00
midoks a1550765aa up 2022-12-31 14:52:39 +08:00
midoks b020f23161 Update info.json 2022-12-31 13:37:11 +08:00
midoks 4afe2061e2 Update mysql.js 2022-12-31 13:32:30 +08:00
midoks ab64c01981 up 2022-12-31 13:14:30 +08:00
midoks 8a97734700 Update index.py 2022-12-31 13:08:03 +08:00
midoks 16b4c64aa5 Update index.py 2022-12-31 13:07:11 +08:00
midoks df2a5919af Update my5.7.cnf 2022-12-30 20:41:51 +08:00
midoks 40a81b794c Update my5.7.cnf 2022-12-30 20:38:40 +08:00
midoks 8fc7ab3abf up 2022-12-30 20:14:28 +08:00
midoks ca4205c89a up 2022-12-30 20:13:35 +08:00
midoks c89b15a645 Update mysql.js 2022-12-30 20:08:00 +08:00
midoks 7a863c4544 修复添加数据库名字判断 2022-12-30 20:07:31 +08:00
midoks 5d81406fdf 优化mysql主从同步UI 2022-12-30 15:21:33 +08:00
midoks cce59c0521 up 2022-12-30 14:56:31 +08:00
Mr Chen 0a5c5aae12 Merge pull request #320 from midoks/midoks-patch-1
Create requirements.txt
2022-12-30 14:25:03 +08:00
Mr Chen 7478426206 Create requirements.txt 2022-12-30 14:24:27 +08:00
midoks c0ed736edb Update index.py 2022-12-30 12:18:35 +08:00
midoks 313eb25ccd Update mysql.js 2022-12-30 12:10:11 +08:00
midoks f58595755b Update index.py 2022-12-30 12:01:02 +08:00
midoks 18a892a576 Update update_dev.sh 2022-12-30 00:32:51 +08:00
midoks 03d558092f Update update_dev.sh 2022-12-30 00:32:20 +08:00
midoks 3cffa9223a Update my5.7.cnf 2022-12-30 00:28:50 +08:00
midoks c0d5aff2f5 mysql配置优化 2022-12-30 00:06:25 +08:00
midoks 3fa4c7804b Update mysql.sql 2022-12-29 23:32:20 +08:00
midoks 22acce8bc0 mysql主从加入新的同步方式 2022-12-29 23:32:14 +08:00
midoks e53e5cd672 Update mw.py 2022-12-28 23:41:02 +08:00
midoks a7d861de22 up 2022-12-28 23:38:37 +08:00
midoks ddeef3c17e up 2022-12-28 23:21:07 +08:00
midoks af733ac28a Merge branch 'master' into dev 2022-12-28 22:34:24 +08:00
Mr Chen 148e2021dc Merge pull request #318 from midoks/dependabot/pip/wheel-0.38.1
Bump wheel from 0.33.6 to 0.38.1
2022-12-28 22:33:23 +08:00
midoks 50c3fe58f4 Update rhel.sh 2022-12-28 21:54:29 +08:00
midoks 5ed3728d4f Update rhel.sh 2022-12-28 21:47:54 +08:00
midoks 9bf06c9d21 Update rhel.sh 2022-12-28 21:47:41 +08:00
midoks 08b3738cfd up 2022-12-28 21:44:18 +08:00
midoks a04f59a3aa Update rhel.sh 2022-12-28 21:31:55 +08:00
midoks 155b8d2b4c Update rhel.sh 2022-12-28 17:26:56 +08:00
dependabot[bot] 039d2794ab Bump wheel from 0.33.6 to 0.38.1
Bumps [wheel](https://github.com/pypa/wheel) from 0.33.6 to 0.38.1.
- [Release notes](https://github.com/pypa/wheel/releases)
- [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst)
- [Commits](https://github.com/pypa/wheel/compare/0.33.6...0.38.1)

---
updated-dependencies:
- dependency-name: wheel
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-26 20:58:18 +00:00
midoks 0d2721523c up 2022-12-25 22:43:34 +08:00
midoks f042665c05 Update install.sh 2022-12-25 18:27:27 +08:00
midoks 0118548c24 up 2022-12-24 22:32:14 +08:00
midoks 1ba6625525 Update libsodium.sh 2022-12-24 22:29:33 +08:00
midoks 293f8ab0af up 2022-12-24 22:21:45 +08:00
midoks dc68868883 Update sodium.sh 2022-12-24 21:57:40 +08:00
midoks 30f835b6b8 Update sodium.sh 2022-12-24 21:53:10 +08:00
midoks 4d90fdfe4f Update install.sh 2022-12-21 22:28:40 +08:00
midoks bb4067aa6b Update install.sh 2022-12-21 22:25:36 +08:00
midoks 5dbf89b872 Update README.md 2022-12-21 22:11:54 +08:00
midoks cc244a8ea5 Update README.md 2022-12-21 21:39:57 +08:00
59 changed files with 2984 additions and 278 deletions
+8 -8
View File
@@ -92,15 +92,15 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.12.0
### 版本更新 0.12.1
此次版本:默认面板名为【大圣面板】。
由于#309问题。先注释。提前发版。
* 安装脚本优化 @hiCasper。
* 数据库[pg/apt/yum/mariadb]计划任务备份ok。
* php源码加入sodium扩展。
* 站点分类问题 #300。
* mysql/mariadb/mysql-apt/mysql-yum增加新的同步方式[同步账户]。
* pureftp安装时自动放行端口。
* 面板ssl,添加【申请Lets证书】功能。
* 站点子域名绑定优化。
* 修复添加数据库名字判断。
* 增加PHP52的隐藏和显示指令。
* 各种细节优化。
### JSDelivr安装地址
+1 -1
View File
@@ -825,7 +825,7 @@ fi
ret_title, json.dumps(a_auth)))
break
if number_of_checks == self._max_check_num:
if number_of_checks == self.__max_check_num:
raise StopIteration(
"错误:已尝试验证{0}次. 最大验证次数为{1}. 验证时间间隔为{2}秒.".format(
number_of_checks,
+1 -1
View File
@@ -736,7 +736,7 @@ class cert_request:
ret_title, json.dumps(a_auth)))
break
if number_of_checks == self._max_check_num:
if number_of_checks == self.__max_check_num:
raise StopIteration(
"错误:已尝试验证{0}次. 最大验证次数为{1}. 验证时间间隔为{2}秒.".format(
number_of_checks,
+54 -4
View File
@@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.12.0'
__version = '0.12.1'
__api_addr = 'data/api.json'
def __init__(self):
@@ -340,11 +340,13 @@ class config_api:
# 获取面板证书
def getPanelSslApi(self):
cert = {}
cert = self.getPanelSslData()
return mw.getJson(cert)
def getPanelSslData(self):
cert = {}
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
if not os.path.exists(certPath):
mw.createSSL()
@@ -352,7 +354,7 @@ class config_api:
cert['certPem'] = mw.readFile(certPath)
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = mw.getCertName(certPath)
return mw.getJson(cert)
return cert
# 保存面板证书
def savePanelSslApi(self):
@@ -378,6 +380,54 @@ class config_api:
mw.writeFile('ssl/input.pl', 'True')
return mw.returnJson(True, '证书已保存!')
# 申请面板let证书
def applyPanelLetSslApi(self):
# check domain is bind?
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
siteName = mw.readFile(bind_domain).strip()
auth_to = mw.getRunDir() + "/tmp"
to_args = {
'domains': [siteName],
'auth_type': 'http',
'auth_to': auth_to,
}
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
src_csrpath = src_letpath + "/fullchain.pem" # 生成证书路径
src_keypath = src_letpath + "/privkey.pem" # 密钥文件路径
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
if not data['status']:
msg = data['msg']
if type(data['msg']) != str:
msg = data['msg'][0]
emsg = data['msg'][1]['challenges'][0]['error']
msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
return mw.returnJson(data['status'], msg, data['msg'])
mw.buildSoftLink(src_csrpath, dst_csrpath, True)
mw.buildSoftLink(src_keypath, dst_keypath, True)
mw.execShell('echo "lets" > "' + dst_letpath + '/README"')
data = self.getPanelSslData()
tmp_well_know = auth_to + '/.well-known'
if os.path.exists(tmp_well_know):
mw.execShell('rm -rf ' + tmp_well_know)
return mw.returnJson(True, '申请成功!', data)
def setPanelDomainApi(self):
domain = request.form.get('domain', '')
+1
View File
@@ -117,6 +117,7 @@ class Sql():
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
# print(sql)
# print(self.__OPT_PARAM)
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
data = result.fetchall()
# 构造字曲系列
+26 -6
View File
@@ -342,6 +342,28 @@ class firewall_api:
status = request.form.get('status', '1')
return mw.getJson(self.setFw(status))
def setFwIptables(self, status):
# iptables特殊处理
if status == '1':
mw.execShell('service iptables save')
mw.execShell('service iptables stop')
else:
# 重新导入数据
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
'0,1000').order('id desc').select()
for x in _list:
port = x['port']
if mw.isIpAddr(port):
cmd = 'iptables -I INPUT -s ' + port + ' -j DROP'
mw.execShell(cmd)
else:
self.addAcceptPort(port)
mw.execShell('service iptables save')
mw.execShell('service iptables start')
def setFw(self, status):
if status == '1':
if self.__isUfw:
@@ -352,8 +374,7 @@ class firewall_api:
elif self.__isMac:
pass
else:
mw.execShell('service iptables save')
mw.execShell('service iptables stop')
self.setFwIptables(status)
else:
if self.__isUfw:
mw.execShell("echo 'y'| ufw enable")
@@ -363,8 +384,7 @@ class firewall_api:
elif self.__isMac:
pass
else:
mw.execShell('service iptables save')
mw.execShell('service iptables restart')
self.setFwIptables(status)
return mw.returnData(True, '设置成功!')
@@ -456,8 +476,8 @@ class firewall_api:
elif self.__isMac:
return False
else:
cmd = "ps -ef|grep iptables |grep -v grep | awk '{print $2}'"
cmd = "systemctl status iptables | grep 'inactive'"
data = mw.execShell(cmd)
if data[0] == '':
if data[0] != '':
return False
return True
+21
View File
@@ -219,6 +219,15 @@ def isInstalledWeb():
return False
def isIpAddr(ip):
check_ip = re.compile(
'^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$')
if check_ip.match(ip):
return True
else:
return False
def restartWeb():
return opWeb("reload")
@@ -490,6 +499,18 @@ def backFile(file, act=None):
execShell("cp -p {0} {1}".format(file, file + file_type))
def removeBackFile(file, act=None):
"""
@name 删除备份配置文件
@param file 需要删除备份文件
@param act 如果存在,则还原默认配置
"""
file_type = "_bak"
if act:
file_type = "_def"
execShell("rm -rf {0}".format(file + file_type))
def restoreFile(file, act=None):
"""
@name 还原配置文件
+46 -12
View File
@@ -817,9 +817,9 @@ class site_api:
if not len(domains):
return mw.returnJson(False, '请选择域名')
file = self.getHostConf(siteName)
if os.path.exists(file):
siteConf = mw.readFile(file)
host_conf_file = self.getHostConf(siteName)
if os.path.exists(host_conf_file):
siteConf = mw.readFile(host_conf_file)
if siteConf.find('301-END') != -1:
return mw.returnJson(False, '检测到您的站点做了301重定向设置,请先关闭重定向!')
@@ -837,7 +837,15 @@ class site_api:
if os.path.exists(proxy_dir_file):
return mw.returnJson(False, '检测到您的站点做了反向代理设置,请先关闭反向代理!')
auth_to = self.getSitePath(siteName)
# fix binddir domain ssl apply question
mw.backFile(host_conf_file)
auth_to = self.getSitePath(siteName)
rep = "\s*root\s*(.+);"
replace_root = "\n\troot " + auth_to + ";"
siteConf = re.sub(rep, replace_root, siteConf)
mw.writeFile(host_conf_file, siteConf)
mw.restartWeb()
to_args = {
'domains': domains,
'auth_type': 'http',
@@ -855,6 +863,7 @@ class site_api:
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
mw.restoreFile(host_conf_file)
if not data['status']:
msg = data['msg']
if type(data['msg']) != str:
@@ -876,6 +885,8 @@ class site_api:
result['csr'] = mw.readFile(src_csrpath)
result['key'] = mw.readFile(src_keypath)
mw.restartWeb()
return mw.returnJson(data['status'], data['msg'], result)
def getAcmeLogsApi(self):
@@ -1118,6 +1129,26 @@ class site_api:
host = self.getHostConf(siteName)
return mw.getJson({'host': host})
def saveHostConfApi(self):
path = request.form.get('path', '')
data = request.form.get('data', '')
encoding = request.form.get('encoding', '')
import files_api
mw.backFile(path)
save_ret_data = files_api.files_api().saveBody(path, data, encoding)
rdata = json.loads(save_ret_data)
if rdata['status']:
isError = mw.checkWebConfig()
if isError != True:
mw.restoreFile(path)
return mw.returnJson(False, 'ERROR: 检测到配置文件有错误,请先排除后再操作<br><br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
mw.restartWeb()
mw.removeBackFile(path)
return save_ret_data
def getRewriteConfApi(self):
siteName = request.form.get('siteName', '')
rewrite = self.getRewriteConf(siteName)
@@ -1211,14 +1242,15 @@ class site_api:
return mw.returnJson(False, '端口范围不合法!')
opid = mw.M('domain').where(
"name=? AND (port=? OR pid=?)", (domain, domain_port, pid)).getField('pid')
if opid:
if mw.M('sites').where('id=?', (opid,)).count():
return mw.returnJson(False, '指定域名已绑定过!')
mw.M('domain').where('pid=?', (opid,)).delete()
"name=? AND (port=? OR pid=?)", (domain_name, domain_port, pid,)).getField('pid')
if opid > 0:
return mw.returnJson(False, '您添加的域名[{}],已绑定!'.format(domain_name))
# if mw.M('sites').where('id=?', (opid,)).count():
# return mw.returnJson(False, '指定域名已绑定过!')
# mw.M('domain').where('pid=?', (opid,)).delete()
if mw.M('binding').where('domain=?', (domain,)).count():
return mw.returnJson(False, '您添加的域名已存在!')
return mw.returnJson(False, '您添加的域名,子目录已绑定!')
self.nginxAddDomain(webname, domain_name, domain_port)
@@ -1270,17 +1302,18 @@ class site_api:
content = content.replace('{$ROOT_DIR}', webdir)
content = content.replace('{$SERVER_MAIN}', siteInfo['name'])
content = content.replace('{$OR_REWRITE}', self.rewritePath)
content = content.replace('{$PHP_DIR}', self.setupPath + '/php')
content = content.replace('{$LOGPATH}', mw.getLogsDir())
conf += "\r\n" + content
shutil.copyfile(filename, '/tmp/backup.conf')
mw.backFile(filename)
mw.writeFile(filename, conf)
conf = mw.readFile(filename)
# 检查配置是否有误
isError = mw.checkWebConfig()
if isError != True:
shutil.copyfile('/tmp/backup.conf', filename)
mw.restoreFile(filename)
return mw.returnJson(False, 'ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
mw.M('binding').add('pid,domain,port,path,addtime',
@@ -1290,6 +1323,7 @@ class site_api:
(siteInfo['name'], dirName, domain))
mw.writeLog('网站管理', msg)
mw.restartWeb()
mw.removeBackFile(filename)
return mw.returnJson(True, '添加成功!')
def delDirBindApi(self):
+1 -1
View File
@@ -17,7 +17,7 @@ server
#ERROR-PAGE-END
#PHP-INFO-START
include enable-php-{$PHPVER}.conf;
include {$PHP_DIR}/conf/enable-php-{$PHPVER}.conf;
#PHP-INFO-END
#REWRITE-START
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sort": 7,
"ps": "简单邮件服务[DEV]",
"ps": "[<b style='color:red;'>DEV</b>]简单邮件服务",
"name": "imail",
"title": "邮件服务",
"shell": "install.sh",
+14
View File
@@ -40,4 +40,18 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`addtime` TEXT
);
-- 从库配置主库的[user]
-- drop table `slave_user`;
CREATE TABLE IF NOT EXISTS `slave_sync_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ip` TEXT,
`port` TEXT,
`user` TEXT,
`pass` TEXT,
`mode` TEXT,
`cmd` TEXT,
`addtime` TEXT
);
+1
View File
@@ -70,6 +70,7 @@ replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
replicate-wild-ignore-table=mysql.%
innodb_data_home_dir = {$SERVER_APP_PATH}/data
+316 -16
View File
@@ -140,20 +140,27 @@ def contentReplace(content):
def pSqliteDb(dbname='databases'):
file = getServerDir() + '/mariadb.db'
name = 'mysql'
if not os.path.exists(file):
import_sql = mw.readFile(getPluginDir() + '/conf/mariadb.sql')
md5_sql = mw.md5(import_sql)
import_sign = False
save_md5_file = getServerDir() + '/import_sql.md5'
if os.path.exists(save_md5_file):
save_md5_sql = mw.readFile(save_md5_file)
if save_md5_sql != md5_sql:
import_sign = True
mw.writeFile(save_md5_file, md5_sql)
else:
mw.writeFile(save_md5_file, md5_sql)
if not os.path.exists(file) or import_sql:
conn = mw.M(dbname).dbPos(getServerDir(), name)
csql = mw.readFile(getPluginDir() + '/conf/mariadb.sql')
csql_list = csql.split(';')
csql_list = import_sql.split(';')
for index in range(len(csql_list)):
conn.execute(csql_list[index], ())
else:
# 现有run
# conn = mw.M(dbname).dbPos(getServerDir(), name)
# csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
# csql_list = csql.split(';')
# for index in range(len(csql_list)):
# conn.execute(csql_list[index], ())
conn = mw.M(dbname).dbPos(getServerDir(), name)
conn = mw.M(dbname).dbPos(getServerDir(), name)
return conn
@@ -280,6 +287,13 @@ def binLog():
return mw.returnJson(True, '设置成功!')
def cleanBinLog():
db = pMysqlDb()
cleanTime = time.strftime('%Y-%m-%d %H:%i:%s', time.localtime())
db.execute("PURGE MASTER LOGS BEFORE '" + cleanTime + "';")
return mw.returnJson(True, '清理BINLOG成功!')
def setSkipGrantTables(v):
'''
设置是否密码验证
@@ -1785,7 +1799,7 @@ def addMasterRepSlaveUser(version=''):
# address = args['address'].strip()
# dataAccess = args['dataAccess'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, username):
return mw.returnJson(False, '用户名不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1806,11 +1820,15 @@ def addMasterRepSlaveUser(version=''):
sql = "GRANT REPLICATION SLAVE ON *.* TO '" + username + \
"'@'%' identified by '" + password + "';"
result = pdb.execute(sql)
result = pdb.execute('FLUSH PRIVILEGES;')
isError = isSqlError(result)
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
psdb.add('username,password,accept,ps,addtime',
(username, password, '%', '', addTime))
@@ -1847,10 +1865,16 @@ def getMasterRepSlaveUserCmd(version):
mode = recognizeDbMode()
# 查找同步点
# SELECT BINLOG_GTID_POS('master1-bin.000002', 561866201);
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_LOG_FILE='" + mstatus[0]["File"] + \
"',MASTER_LOG_POS=" + \
str(mstatus[0]["Position"]) + \
",MASTER_USE_GTID=slave_pos,MASTER_CONNECT_RETRY=10;"
else:
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
@@ -1936,6 +1960,123 @@ def getSlaveSSHList(version=''):
return mw.getJson(data)
def getSlaveSyncUserByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').where(
"ip=?", (ip,)).select()
return mw.returnJson(True, 'ok', data)
def addSlaveSyncUser(version=''):
import base64
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
if ip == "":
return mw.returnJson(True, 'ok')
data = checkArgs(args, ['port', 'user', 'pass', 'mode'])
if not data[0]:
return data[1]
cmd = args['cmd']
port = args['port']
user = args['user']
apass = args['pass']
mode = args['mode']
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip').where("ip=?", (ip,)).select()
if len(data) > 0:
res = conn.where("ip=?", (ip,)).save(
'port,user,pass,mode,cmd', (port, user, apass, mode, cmd))
else:
conn.add('ip,port,user,cmd,user,pass,mode,addtime',
(ip, port, user, cmd, user, apass, mode, addTime))
return mw.returnJson(True, '设置成功!')
def delSlaveSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
conn.where("ip=?", (ip,)).delete()
return mw.returnJson(True, '删除成功!')
def getSlaveSyncUserList(version=''):
args = getArgs()
data = checkArgs(args, ['page', 'page_size'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
conn = pSqliteDb('slave_sync_user')
limit = str((page - 1) * page_size) + ',' + str(page_size)
field = 'id,ip,port,user,pass,cmd,addtime'
clist = conn.field(field).limit(limit).order('id desc').select()
count = conn.count()
data = {}
_page = {}
_page['count'] = count
_page['p'] = page
_page['row'] = page_size
_page['tojs'] = args['tojs']
data['page'] = mw.getPage(_page)
data['data'] = clist
return mw.getJson(data)
def getSyncModeFile():
return getServerDir() + "/sync.mode"
def getSlaveSyncMode(version):
sync_mode = getSyncModeFile()
if os.path.exists(sync_mode):
mode = mw.readFile(sync_mode).strip()
return mw.returnJson(True, 'ok', mode)
return mw.returnJson(False, 'fail')
def setSlaveSyncMode(version):
args = getArgs()
data = checkArgs(args, ['mode'])
if not data[0]:
return data[1]
mode = args['mode']
sync_mode = getSyncModeFile()
if mode == 'none':
os.remove(sync_mode)
else:
mw.writeFile(sync_mode, mode)
return mw.returnJson(True, '设置成功', mode)
def getSlaveSSHByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
@@ -2013,8 +2154,6 @@ def getSlaveList(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
# print(dlist)
ret = []
for x in range(0, len(dlist)):
tmp = {}
@@ -2024,6 +2163,24 @@ def getSlaveList(version=''):
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"]
tmp['Last_Error'] = dlist[x]["Last_Error"]
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
tmp['Error'] = ''
if tmp['Last_Error'] != '':
tmp['Error'] = tmp['Last_Error']
if tmp['Last_IO_Error'] != '':
tmp['Error'] = tmp['Last_IO_Error']
if tmp['Last_SQL_Error'] != '':
tmp['Error'] = tmp['Last_SQL_Error']
if tmp['Error'] == '':
tmp['Error'] = tmp['Slave_SQL_Running_State']
ret.append(tmp)
data = {}
data['data'] = ret
@@ -2040,6 +2197,47 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return initSlaveStatusSSH(version)
if mode == 'sync-user':
return initSlaveStatusSyncUser(version)
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
if len(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'
local_mode = recognizeDbMode()
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
# print(u['cmd'])
t = db.query(u['cmd'])
# print(t)
db.query("start slave")
return mw.returnJson(True, '初始化成功!')
def initSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) > 0:
@@ -2110,6 +2308,41 @@ def initSlaveStatus(version=''):
def setSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
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')
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']
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')
@@ -2178,6 +2411,61 @@ def writeDbSyncStatus(data):
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return doFullSyncSSH(version)
if mode == 'sync-user':
return doFullSyncUser(version)
def doFullSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
sync_db = args['db']
db = pMysqlDb()
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
bak_file = '/tmp/tmp.sql'
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
mw.execShell(my_import_cmd)
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + bak_file)
return True
def doFullSyncSSH(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
@@ -2483,6 +2771,18 @@ if __name__ == "__main__":
print(delSlaveSSH(version))
elif func == 'update_slave_ssh':
print(updateSlaveSSH(version))
elif func == 'get_slave_sync_user_list':
print(getSlaveSyncUserList(version))
elif func == 'get_slave_sync_user_by_ip':
print(getSlaveSyncUserByIp(version))
elif func == 'add_slave_sync_user':
print(addSlaveSyncUser(version))
elif func == 'del_slave_sync_user':
print(delSlaveSyncUser(version))
elif func == 'get_slave_sync_mode':
print(getSlaveSyncMode(version))
elif func == 'set_slave_sync_mode':
print(setSlaveSyncMode(version))
elif func == 'init_slave_status':
print(initSlaveStatus(version))
elif func == 'set_slave_status':
+273 -9
View File
@@ -39,7 +39,7 @@ function myPostN(method,args,callback, title){
if (typeof(title) != 'undefined'){
_title = title;
}
$.post('/plugins/run', {name:'mysql', func:method, args:_args}, function(data) {
$.post('/plugins/run', {name:'mariadb', func:method, args:_args}, function(data) {
if(typeof(callback) == 'function'){
callback(data);
}
@@ -655,8 +655,8 @@ function addDatabase(type){
<span class='tname'>数据库名</span>\
<div class='info-r'><input name='name' class='bt-input-text mr5' placeholder='新的数据库名称' type='text' style='width:65%' value=''>\
<select class='bt-input-text mr5 codeing_a5nGsm' name='codeing' style='width:27%'>\
<option value='utf8'>utf-8</option>\
<option value='utf8mb4'>utf8mb4</option>\
<option value='utf8'>utf-8</option>\
<option value='gbk'>gbk</option>\
<option value='big5'>big5</option>\
</select>\
@@ -1504,7 +1504,7 @@ function getMasterRepSlaveUserCmd(username, db=''){
title: '同步命令',
area: '500px',
content:"<form class='bt-form pd20 pb70' id='add_master'>\
<div class='line'>"+cmd+"</div>\
<div class='line' style='word-wrap: break-word;word-break: normal;'>"+cmd+"</div>\
<div class='bt-form-submit-btn'>\
<button type='button' class='btn btn-success btn-sm btn-title class-copy-cmd'>复制</button>\
</div>\
@@ -1795,11 +1795,27 @@ function addSlaveSSH(ip=''){
}
function delSlaveSSH(ip){
myPost('del_slave_ssh', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
getSlaveSSHPage();
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSSHPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
function delSlaveSyncUser(ip){
myPost('del_slave_sync_user', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
@@ -1848,6 +1864,234 @@ function getSlaveSSHPage(page=1){
});
}
function addSlaveSyncUser(ip=''){
myPost('get_slave_sync_user_by_ip', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var ip = '127.0.0.1';
var port = "22";
var cmd = '';
var user = 'input_sync_user';
var pass = 'input_sync_pwd';
var mode = '0';
if (rdata.data.length>0){
ip = rdata.data[0]['ip'];
port = rdata.data[0]['port'];
cmd = rdata.data[0]['cmd'];
user = rdata.data[0]['user'];
pass = rdata.data[0]['pass'];
mode = rdata.data[0]['mode'];
}
var index = layer.open({
type: 1,
area: ['500px','470px'],
title: '同步账户',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:["确认","取消"],
content: "<form class='bt-form pd20'>\
<div class='line'><span class='tname'>IP</span><div class='info-r'><input name='ip' class='bt-input-text mr5' type='text' style='width:330px;' value='"+ip+"'></div></div>\
<div class='line'><span class='tname'>端口</span><div class='info-r'><input name='port' class='bt-input-text mr5' type='number' style='width:330px;' value='"+port+"'></div></div>\
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
<div class='line'>\
<span class='tname'>CMD[必填]</span>\
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
</div>\
<input type='hidden' name='mode' value='"+mode+"' />\
</form>",
success:function(){
$('textarea[name="cmd"]').html(cmd);
$('textarea[name="cmd"]').change(function(){
var val = $(this).val();
var vlist = val.split(',');
var a = {};
for (var i in vlist) {
var tmp = toTrim(vlist[i]);
var tmp_a = tmp.split(" ");
var real_tmp = tmp_a[tmp_a.length-1];
var kv = real_tmp.split("=");
a[kv[0]] = kv[1].replace("'",'').replace("'",'');
}
$('input[name="ip"]').val(a['MASTER_HOST']);
$('input[name="port"]').val(a['MASTER_PORT']);
$('input[name="user"]').val(a['MASTER_USER']);
$('input[name="pass"]').val(a['MASTER_PASSWORD']);
console.log(a['MASTER_USE_GTID'],typeof(a['MASTER_USE_GTID']));
if (typeof(a['MASTER_USE_GTID']) != 'undefined' ){
$('input[name="mode"]').val('1');
}
});
},
yes:function(index){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var user = $('input[name="user"]').val();
var pass = $('input[name="pass"]').val();
var cmd = $('textarea[name="cmd"]').val();
var mode = $('input[name="mode"]').val();
var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
myPost('add_slave_sync_user', data, function(ret_data){
layer.close(index);
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2},600);
});
}
});
});
}
function getSlaveSyncUserPage(page=1){
var _data = {};
_data['page'] = page;
_data['page_size'] = 5;
_data['tojs'] ='getSlaveSyncUserPage';
myPost('get_slave_sync_user_list', _data, function(data){
var layerId = null;
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e) {
console.log(e);
}
var list = '';
var user_list = rdata['data'];
for (i in user_list) {
var ip = user_list[i]['ip'];
var port = user_list[i]['port'];
var user = user_list[i]['user'];
var apass = user_list[i]['pass'];
var cmd = '未设置';
if (user_list[i]['cmd']!=''){
cmd = '已设置';
}
list += '<tr><td>'+ip+'</td>\
<td>'+port+'</td>\
<td>'+user+'</td>\
<td>'+apass+'</td>\
<td>'+cmd+'</td>\
<td>\
<a class="btlink" onclick="addSlaveSyncUser(\''+ip+'\');">修改</a> | \
<a class="btlink" onclick="delSlaveSyncUser(\''+ip+'\');">删除</a>\
</td>\
</tr>';
}
$('.get-slave-ssh-list tbody').html(list);
$('.dataTables_paginate_4').html(rdata['page']);
});
}
function getSlaveCfg(){
myPost('get_slave_sync_mode', '', function(data){
var rdata = $.parseJSON(data.data);
var mode_none = 'success';
var mode_ssh = 'danger';
var mode_sync_user = 'danger';
if(rdata.status){
var mode_none = 'danger';
if (rdata.data == 'ssh'){
var mode_ssh = 'success';
var mode_sync_user = 'danger';
} else {
var mode_ssh = 'danger';
var mode_sync_user = 'success';
}
}
layerId = layer.open({
type: 1,
title: '同步配置',
area: ['400px','180px'],
content:"<div class='bt-form pd20 c6'>\
<p class='conf_p'>\
<span class='f14 c6 mr20'>当前从库同步模式</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-"+mode_none+" btn-xs slave-db-mode btn-none'>无</button>\
<button class='btn btn-"+mode_ssh+" btn-xs slave-db-mode btn-ssh'>SSH</button>\
<button class='btn btn-"+mode_sync_user+" btn-xs slave-db-mode btn-sync-user'>同步账户</button>\
</p>\
<hr />\
<p class='conf_p'>\
<span class='f14 c6 mr20'>配置设置</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-success btn-xs btn-slave-ssh'>SSH</button>\
<button class='btn btn-success btn-xs btn-slave-user'>同步账户</button>\
</p>\
</div>",
success:function(){
$('.btn-slave-ssh').click(function(){
getSlaveSSHList();
});
$('.btn-slave-user').click(function(){
getSlaveUserList();
});
$('.slave-db-mode').click(function(){
var _this = this;
var mode = 'none';
if ($(this).hasClass('btn-ssh')){
mode = 'ssh';
}
if ($(this).hasClass('btn-sync-user')){
mode = 'sync-user';
}
myPost('set_slave_sync_mode', {mode:mode}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
$('.slave-db-mode').remove('btn-success').addClass('btn-danger');
$(_this).removeClass('btn-danger').addClass('btn-success');
},{icon:rdata.status?1:2},2000);
});
});
}
});
});
}
function getSlaveUserList(){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
page += '<div class="table_toolbar" style="left:0px;"><span class="sync btn btn-default btn-sm" onclick="addSlaveSyncUser()" title="">添加同步账户</span></div>';
layerId = layer.open({
type: 1,
title: '同步账户列表',
area: '500px',
content:"<div class='bt-form pd20 c6'>\
<div class='divtable mtb10'>\
<div><table class='table table-hover get-slave-ssh-list'>\
<thead><tr><th>IP</th><th>PORT</th><th>同步账户</th><th>同步密码</th><th>CMD</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table></div>\
"+page +"\
</div>\
</div>",
success:function(){
getSlaveSyncUserPage(1);
}
});
}
function getSlaveSSHList(page=1){
@@ -1968,7 +2212,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
var status = "异常";
var status = "<a class='btlink db_error'>异常</>";
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
status = "正常";
}
@@ -2010,6 +2254,26 @@ function masterOrSlaveConf(version=''){
// <span class="sync btn btn-default btn-sm" onclick="getMasterRepSlaveList()" title="">添加</span>\
// </div>
$(".table_slave_status_list").html(con);
$('.db_error').click(function(){
layer.open({
type: 1,
title: '同步异常信息',
area: '500px',
content:"<form class='bt-form pd20 pb70'>\
<div class='line'>"+v['Error']+"</div>\
<div class='bt-form-submit-btn'>\
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
</div>\
</form>",
success:function(){
copyText(v['Error']);
$('.class-copy-db-err').click(function(){
copyText(v['Error']);
});
}
});
});
});
}
@@ -2087,7 +2351,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Slave[从]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.slave_status ? 'btn-danger' : 'btn-success')+' btn-xs btn-slave">'+(!rdata.slave_status ? '未启动' : '已启动') +'</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveSSHList()" >[主]SSH配置</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveCfg()" >同步配置</button>\
<button class="btn btn-success btn-xs" onclick="initSlaveStatus()" >初始化</button>\
</p>\
<hr/>\
@@ -2161,10 +2425,10 @@ function masterOrSlaveConf(version=''){
getMasterDbList();
}
if (rdata.slave_status){
// if (rdata.slave_status){
getAsyncMasterDbList();
getAsyncDataList()
}
// }
});
}
getMasterStatus();
+5 -4
View File
@@ -36,11 +36,12 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
#skip-external-locking
#skip-grant-tables
#loose-skip-innodb
skip_name_resolve = 1
skip-ssl
#skip-networking
#skip-name-resolve
#skip-external-locking
#loose-skip-innodb
#skip-grant-tables
log-bin=mysql-bin
binlog_format=mixed
+13
View File
@@ -40,4 +40,17 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`addtime` TEXT
);
-- 从库配置主库的[user]
-- drop table `slave_user`;
CREATE TABLE IF NOT EXISTS `slave_sync_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ip` TEXT,
`port` TEXT,
`user` TEXT,
`pass` TEXT,
`mode` TEXT,
`cmd` TEXT,
`addtime` TEXT
);
+1
View File
@@ -13,6 +13,7 @@
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mysql-apt',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
+348 -26
View File
@@ -122,20 +122,27 @@ def contentReplace(content):
def pSqliteDb(dbname='databases'):
file = getServerDir() + '/mysql.db'
name = 'mysql'
if not os.path.exists(file):
import_sql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
md5_sql = mw.md5(import_sql)
import_sign = False
save_md5_file = getServerDir() + '/import_sql.md5'
if os.path.exists(save_md5_file):
save_md5_sql = mw.readFile(save_md5_file)
if save_md5_sql != md5_sql:
import_sign = True
mw.writeFile(save_md5_file, md5_sql)
else:
mw.writeFile(save_md5_file, md5_sql)
if not os.path.exists(file) or import_sql:
conn = mw.M(dbname).dbPos(getServerDir(), name)
csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
csql_list = csql.split(';')
csql_list = import_sql.split(';')
for index in range(len(csql_list)):
conn.execute(csql_list[index], ())
else:
# 现有run
# conn = mw.M(dbname).dbPos(getServerDir(), name)
# csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
# csql_list = csql.split(';')
# for index in range(len(csql_list)):
# conn.execute(csql_list[index], ())
conn = mw.M(dbname).dbPos(getServerDir(), name)
conn = mw.M(dbname).dbPos(getServerDir(), name)
return conn
@@ -154,9 +161,16 @@ def pMysqlDb():
def initDreplace(version=''):
my_dir = getServerDir() + '/etc'
if not os.path.exists(my_dir):
os.mkdir(my_dir)
conf_dir = getServerDir() + '/etc'
mode_dir = conf_dir + '/mode'
conf_list = [
conf_dir,
mode_dir,
]
for conf in conf_list:
if not os.path.exists(conf):
os.mkdir(conf)
tmp_dir = getServerDir() + '/tmp'
if not os.path.exists(tmp_dir):
@@ -164,12 +178,26 @@ def initDreplace(version=''):
mw.execShell("chown -R mysql:mysql " + tmp_dir)
mw.execShell("chmod 750 " + tmp_dir)
mysql_conf = my_dir + '/my.cnf'
if not os.path.exists(mysql_conf):
mysql_conf_tpl = getPluginDir() + '/conf/my' + version + '.cnf'
content = mw.readFile(mysql_conf_tpl)
my_conf = conf_dir + '/my.cnf'
if not os.path.exists(my_conf):
tpl = getPluginDir() + '/conf/my' + version + '.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(mysql_conf, content)
mw.writeFile(my_conf, content)
classic_conf = mode_dir + '/classic.cnf'
if not os.path.exists(classic_conf):
tpl = getPluginDir() + '/conf/classic.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(classic_conf, content)
gtid_conf = mode_dir + '/gtid.cnf'
if not os.path.exists(gtid_conf):
tpl = getPluginDir() + '/conf/gtid.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(gtid_conf, content)
# systemd
systemDir = mw.systemdCfgDir()
@@ -745,10 +773,13 @@ def importDbExternal():
pwd + ' ' + name + ' < ' + import_sql
# print(mysql_cmd)
os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if ext != 'sql':
os.remove(import_sql)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -774,7 +805,12 @@ def importDbBackup():
' ' + name + ' < ' + file_path_sql
# print(mysql_cmd)
os.system(mysql_cmd)
# os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -1104,7 +1140,7 @@ def addDb():
dataAccess = args['dataAccess'].strip()
ps = args['ps'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, args['name']):
return mw.returnJson(False, '数据库名称不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1772,7 +1808,7 @@ def addMasterRepSlaveUser(version=''):
# address = args['address'].strip()
# dataAccess = args['dataAccess'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, username):
return mw.returnJson(False, '用户名不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1800,17 +1836,18 @@ def addMasterRepSlaveUser(version=''):
if isError != None:
return isError
sql = "FLUSH PRIVILEGES;"
pdb.execute(sql)
else:
sql = "GRANT REPLICATION SLAVE ON *.* TO '" + username + \
"'@'%' identified by '" + password + "';"
result = pdb.execute(sql)
result = pdb.execute('FLUSH PRIVILEGES;')
isError = isSqlError(result)
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
psdb.add('username,password,accept,ps,addtime',
(username, password, '%', '', addTime))
@@ -1947,6 +1984,123 @@ def getSlaveSSHList(version=''):
return mw.getJson(data)
def getSlaveSyncUserByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').where(
"ip=?", (ip,)).select()
return mw.returnJson(True, 'ok', data)
def addSlaveSyncUser(version=''):
import base64
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
if ip == "":
return mw.returnJson(True, 'ok')
data = checkArgs(args, ['port', 'user', 'pass', 'mode'])
if not data[0]:
return data[1]
cmd = args['cmd']
port = args['port']
user = args['user']
apass = args['pass']
mode = args['mode']
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip').where("ip=?", (ip,)).select()
if len(data) > 0:
res = conn.where("ip=?", (ip,)).save(
'port,user,pass,mode,cmd', (port, user, apass, mode, cmd))
else:
conn.add('ip,port,user,cmd,user,pass,mode,addtime',
(ip, port, user, cmd, user, apass, mode, addTime))
return mw.returnJson(True, '设置成功!')
def delSlaveSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
conn.where("ip=?", (ip,)).delete()
return mw.returnJson(True, '删除成功!')
def getSlaveSyncUserList(version=''):
args = getArgs()
data = checkArgs(args, ['page', 'page_size'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
conn = pSqliteDb('slave_sync_user')
limit = str((page - 1) * page_size) + ',' + str(page_size)
field = 'id,ip,port,user,pass,cmd,addtime'
clist = conn.field(field).limit(limit).order('id desc').select()
count = conn.count()
data = {}
_page = {}
_page['count'] = count
_page['p'] = page
_page['row'] = page_size
_page['tojs'] = args['tojs']
data['page'] = mw.getPage(_page)
data['data'] = clist
return mw.getJson(data)
def getSyncModeFile():
return getServerDir() + "/sync.mode"
def getSlaveSyncMode(version):
sync_mode = getSyncModeFile()
if os.path.exists(sync_mode):
mode = mw.readFile(sync_mode).strip()
return mw.returnJson(True, 'ok', mode)
return mw.returnJson(False, 'fail')
def setSlaveSyncMode(version):
args = getArgs()
data = checkArgs(args, ['mode'])
if not data[0]:
return data[1]
mode = args['mode']
sync_mode = getSyncModeFile()
if mode == 'none':
os.remove(sync_mode)
else:
mw.writeFile(sync_mode, mode)
return mw.returnJson(True, '设置成功', mode)
def getSlaveSSHByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
@@ -2033,6 +2187,24 @@ def getSlaveList(version=''):
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"]
tmp['Last_Error'] = dlist[x]["Last_Error"]
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
tmp['Error'] = ''
if tmp['Last_Error'] != '':
tmp['Error'] = tmp['Last_Error']
if tmp['Last_IO_Error'] != '':
tmp['Error'] = tmp['Last_IO_Error']
if tmp['Last_SQL_Error'] != '':
tmp['Error'] = tmp['Last_SQL_Error']
if tmp['Error'] == '':
tmp['Error'] = tmp['Slave_SQL_Running_State']
ret.append(tmp)
data = {}
data['data'] = ret
@@ -2049,6 +2221,47 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return initSlaveStatusSSH(version)
if mode == 'sync-user':
return initSlaveStatusSyncUser(version)
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
if len(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'
local_mode = recognizeDbMode()
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
t = db.query(u['cmd'])
# print(t)
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
def initSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) > 0:
@@ -2117,6 +2330,41 @@ def initSlaveStatus(version=''):
def setSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
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')
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']
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')
@@ -2185,6 +2433,68 @@ def writeDbSyncStatus(data):
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return doFullSyncSSH(version)
if mode == 'sync-user':
return doFullSyncUser(version)
def doFullSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
sync_db = args['db']
db = pMysqlDb()
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
bak_file = '/tmp/tmp.sql'
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
mode = recognizeDbMode()
if mode == 'gtid':
dmp_option = ' --set-gtid-purged=off '
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 + " " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
mw.execShell(my_import_cmd)
if version == '8.0':
db.query("start slave user='{}' password='{}';".format(user, apass))
else:
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + bak_file)
return True
def doFullSyncSSH(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
@@ -2516,6 +2826,18 @@ if __name__ == "__main__":
print(delSlaveSSH(version))
elif func == 'update_slave_ssh':
print(updateSlaveSSH(version))
elif func == 'get_slave_sync_user_list':
print(getSlaveSyncUserList(version))
elif func == 'get_slave_sync_user_by_ip':
print(getSlaveSyncUserByIp(version))
elif func == 'add_slave_sync_user':
print(addSlaveSyncUser(version))
elif func == 'del_slave_sync_user':
print(delSlaveSyncUser(version))
elif func == 'get_slave_sync_mode':
print(getSlaveSyncMode(version))
elif func == 'set_slave_sync_mode':
print(setSlaveSyncMode(version))
elif func == 'init_slave_status':
print(initSlaveStatus(version))
elif func == 'set_slave_status':
+1 -1
View File
@@ -4,7 +4,7 @@
"tip":"soft",
"name":"mysql-apt",
"type":"运行环境",
"ps":"[<b style='color:red;'>潜龙勿用</b>]一种关系数据库管理系统[debian,ubuntu](极速安装)",
"ps":"一种关系数据库管理系统[debian,ubuntu](极速安装)",
"todo_versions":["5.7","8.0"],
"versions":["5.7","8.0"],
"shell":"install.sh",
+275 -14
View File
@@ -731,7 +731,7 @@ function addDatabase(type){
layer.close(index);
dbList();
}
},{icon: rdata.status ? 1 : 2},600);
},{icon: rdata.status ? 1 : 2}, 2000);
});
}
});
@@ -1545,13 +1545,9 @@ function getMasterRepSlaveUserCmd(username, db=''){
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(){
showMsg(rdata.msg, function(){
getMasterRepSlaveList();
},1000);
},{icon: rdata.status ? 1 : 2},1000)
});
}
@@ -1821,8 +1817,23 @@ function addSlaveSSH(ip=''){
function delSlaveSSH(ip){
myPost('del_slave_ssh', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
getSlaveSSHPage();
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSSHPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
function delSlaveSyncUser(ip){
myPost('del_slave_sync_user', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
@@ -1872,6 +1883,237 @@ function getSlaveSSHPage(page=1){
}
function addSlaveSyncUser(ip=''){
myPost('get_slave_sync_user_by_ip', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var ip = '127.0.0.1';
var port = "22";
var cmd = '';
var user = 'input_sync_user';
var pass = 'input_sync_pwd';
var mode = '0';
if (rdata.data.length>0){
ip = rdata.data[0]['ip'];
port = rdata.data[0]['port'];
cmd = rdata.data[0]['cmd'];
user = rdata.data[0]['user'];
pass = rdata.data[0]['pass'];
mode = rdata.data[0]['mode'];
}
var index = layer.open({
type: 1,
area: ['500px','470px'],
title: '同步账户',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:["确认","取消"],
content: "<form class='bt-form pd20'>\
<div class='line'><span class='tname'>IP</span><div class='info-r'><input name='ip' class='bt-input-text mr5' type='text' style='width:330px;' value='"+ip+"'></div></div>\
<div class='line'><span class='tname'>端口</span><div class='info-r'><input name='port' class='bt-input-text mr5' type='number' style='width:330px;' value='"+port+"'></div></div>\
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
<div class='line'>\
<span class='tname'>CMD[最好填好]</span>\
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
</div>\
<input type='hidden' name='mode' value='"+mode+"' />\
</form>",
success:function(){
$('textarea[name="cmd"]').html(cmd);
$('textarea[name="cmd"]').change(function(){
var val = $(this).val();
var vlist = val.split(',');
var a = {};
for (var i in vlist) {
var tmp = toTrim(vlist[i]);
var tmp_a = tmp.split(" ");
var real_tmp = tmp_a[tmp_a.length-1];
var kv = real_tmp.split("=");
a[kv[0]] = kv[1].replace("'",'').replace("'",'');
}
$('input[name="ip"]').val(a['MASTER_HOST']);
$('input[name="port"]').val(a['MASTER_PORT']);
$('input[name="user"]').val(a['MASTER_USER']);
$('input[name="pass"]').val(a['MASTER_PASSWORD']);
console.log(a['MASTER_AUTO_POSITION'],typeof(a['MASTER_AUTO_POSITION']));
if (typeof(a['MASTER_AUTO_POSITION']) != 'undefined' ){
$('input[name="mode"]').val('1');
}
});
},
yes:function(index){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var user = $('input[name="user"]').val();
var pass = $('input[name="pass"]').val();
var cmd = $('textarea[name="cmd"]').val();
var mode = $('input[name="mode"]').val();
var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
myPost('add_slave_sync_user', data, function(ret_data){
layer.close(index);
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2},600);
});
}
});
});
}
function getSlaveSyncUserPage(page=1){
var _data = {};
_data['page'] = page;
_data['page_size'] = 5;
_data['tojs'] ='getSlaveSyncUserPage';
myPost('get_slave_sync_user_list', _data, function(data){
var layerId = null;
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e) {
console.log(e);
}
var list = '';
var user_list = rdata['data'];
for (i in user_list) {
var ip = user_list[i]['ip'];
var port = user_list[i]['port'];
var user = user_list[i]['user'];
var apass = user_list[i]['pass'];
var cmd = '未设置';
if (user_list[i]['cmd']!=''){
cmd = '已设置';
}
list += '<tr><td>'+ip+'</td>\
<td>'+port+'</td>\
<td>'+user+'</td>\
<td>'+apass+'</td>\
<td>'+cmd+'</td>\
<td>\
<a class="btlink" onclick="addSlaveSyncUser(\''+ip+'\');">修改</a> | \
<a class="btlink" onclick="delSlaveSyncUser(\''+ip+'\');">删除</a>\
</td>\
</tr>';
}
$('.get-slave-ssh-list tbody').html(list);
$('.dataTables_paginate_4').html(rdata['page']);
});
}
function getSlaveCfg(){
myPost('get_slave_sync_mode', '', function(data){
var rdata = $.parseJSON(data.data);
var mode_none = 'success';
var mode_ssh = 'danger';
var mode_sync_user = 'danger';
if(rdata.status){
var mode_none = 'danger';
if (rdata.data == 'ssh'){
var mode_ssh = 'success';
var mode_sync_user = 'danger';
} else {
var mode_ssh = 'danger';
var mode_sync_user = 'success';
}
}
layerId = layer.open({
type: 1,
title: '同步配置',
area: ['400px','180px'],
content:"<div class='bt-form pd20 c6'>\
<p class='conf_p'>\
<span class='f14 c6 mr20'>当前从库同步模式</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-"+mode_none+" btn-xs slave-db-mode btn-none'>无</button>\
<button class='btn btn-"+mode_ssh+" btn-xs slave-db-mode btn-ssh'>SSH</button>\
<button class='btn btn-"+mode_sync_user+" btn-xs slave-db-mode btn-sync-user'>同步账户</button>\
</p>\
<hr />\
<p class='conf_p'>\
<span class='f14 c6 mr20'>配置设置</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-success btn-xs btn-slave-ssh'>SSH</button>\
<button class='btn btn-success btn-xs btn-slave-user'>同步账户</button>\
</p>\
</div>",
success:function(){
$('.btn-slave-ssh').click(function(){
getSlaveSSHList();
});
$('.btn-slave-user').click(function(){
getSlaveUserList();
});
$('.slave-db-mode').click(function(){
var _this = this;
var mode = 'none';
if ($(this).hasClass('btn-ssh')){
mode = 'ssh';
}
if ($(this).hasClass('btn-sync-user')){
mode = 'sync-user';
}
myPost('set_slave_sync_mode', {mode:mode}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
$('.slave-db-mode').remove('btn-success').addClass('btn-danger');
$(_this).removeClass('btn-danger').addClass('btn-success');
},{icon:rdata.status?1:2},2000);
});
});
}
});
});
}
function getSlaveUserList(){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
page += '<div class="table_toolbar" style="left:0px;"><span class="sync btn btn-default btn-sm" onclick="addSlaveSyncUser()" title="">添加同步账户</span></div>';
layerId = layer.open({
type: 1,
title: '同步账户列表',
area: '500px',
content:"<div class='bt-form pd20 c6'>\
<div class='divtable mtb10'>\
<div><table class='table table-hover get-slave-ssh-list'>\
<thead><tr><th>IP</th><th>PORT</th><th>同步账户</th><th>同步密码</th><th>CMD</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table></div>\
"+page +"\
</div>\
</div>",
success:function(){
getSlaveSyncUserPage(1);
}
});
}
function getSlaveSSHList(page=1){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
@@ -1991,7 +2233,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
var status = "异常";
var status = "<a class='btlink db_error'>异常</>";
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
status = "正常";
}
@@ -2033,6 +2275,26 @@ function masterOrSlaveConf(version=''){
// <span class="sync btn btn-default btn-sm" onclick="getMasterRepSlaveList()" title="">添加</span>\
// </div>
$(".table_slave_status_list").html(con);
$('.db_error').click(function(){
layer.open({
type: 1,
title: '同步异常信息',
area: '500px',
content:"<form class='bt-form pd20 pb70'>\
<div class='line'>"+v['Error']+"</div>\
<div class='bt-form-submit-btn'>\
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
</div>\
</form>",
success:function(){
copyText(v['Error']);
$('.class-copy-db-err').click(function(){
copyText(v['Error']);
});
}
});
});
});
}
@@ -2079,7 +2341,6 @@ function masterOrSlaveConf(version=''){
});
}
function getMasterStatus(){
myPost('get_master_status', '', function(rdata){
@@ -2110,7 +2371,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Slave[从]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.slave_status ? 'btn-danger' : 'btn-success')+' btn-xs btn-slave">'+(!rdata.slave_status ? '未启动' : '已启动') +'</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveSSHList()" >[主]SSH配置</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveCfg()" >同步配置</button>\
<button class="btn btn-success btn-xs" onclick="initSlaveStatus()" >初始化</button>\
</p>\
<hr/>\
@@ -2184,10 +2445,10 @@ function masterOrSlaveConf(version=''){
getMasterDbList();
}
if (rdata.slave_status){
// if (rdata.slave_status){
getAsyncMasterDbList();
getAsyncDataList()
}
// }
});
}
getMasterStatus();
+5 -4
View File
@@ -37,11 +37,12 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
#skip-external-locking
#skip-grant-tables
#loose-skip-innodb
skip_name_resolve = 1
skip-ssl
#skip-networking
#skip-name-resolve
#skip-external-locking
#loose-skip-innodb
#skip-grant-tables
log-bin=mysql-bin
binlog_format=mixed
+13
View File
@@ -40,4 +40,17 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`addtime` TEXT
);
-- 从库配置主库的[user]
-- drop table `slave_user`;
CREATE TABLE IF NOT EXISTS `slave_sync_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ip` TEXT,
`port` TEXT,
`user` TEXT,
`pass` TEXT,
`mode` TEXT,
`cmd` TEXT,
`addtime` TEXT
);
+1
View File
@@ -13,6 +13,7 @@
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mysql-yum',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
+335 -28
View File
@@ -129,20 +129,27 @@ def contentReplace(content):
def pSqliteDb(dbname='databases'):
file = getServerDir() + '/mysql.db'
name = 'mysql'
if not os.path.exists(file):
import_sql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
md5_sql = mw.md5(import_sql)
import_sign = False
save_md5_file = getServerDir() + '/import_sql.md5'
if os.path.exists(save_md5_file):
save_md5_sql = mw.readFile(save_md5_file)
if save_md5_sql != md5_sql:
import_sign = True
mw.writeFile(save_md5_file, md5_sql)
else:
mw.writeFile(save_md5_file, md5_sql)
if not os.path.exists(file) or import_sql:
conn = mw.M(dbname).dbPos(getServerDir(), name)
csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
csql_list = csql.split(';')
csql_list = import_sql.split(';')
for index in range(len(csql_list)):
conn.execute(csql_list[index], ())
else:
# 现有run
# conn = mw.M(dbname).dbPos(getServerDir(), name)
# csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
# csql_list = csql.split(';')
# for index in range(len(csql_list)):
# conn.execute(csql_list[index], ())
conn = mw.M(dbname).dbPos(getServerDir(), name)
conn = mw.M(dbname).dbPos(getServerDir(), name)
return conn
@@ -161,9 +168,16 @@ def pMysqlDb():
def initDreplace(version=''):
my_dir = getServerDir() + '/etc'
if not os.path.exists(my_dir):
os.mkdir(my_dir)
conf_dir = getServerDir() + '/etc'
mode_dir = conf_dir + '/mode'
conf_list = [
conf_dir,
mode_dir,
]
for conf in conf_list:
if not os.path.exists(conf):
os.mkdir(conf)
tmp_dir = getServerDir() + '/tmp'
if not os.path.exists(tmp_dir):
@@ -171,12 +185,26 @@ def initDreplace(version=''):
mw.execShell("chown -R mysql:mysql " + tmp_dir)
mw.execShell("chmod 750 " + tmp_dir)
mysql_conf = my_dir + '/my.cnf'
if not os.path.exists(mysql_conf):
mysql_conf_tpl = getPluginDir() + '/conf/my' + version + '.cnf'
content = mw.readFile(mysql_conf_tpl)
my_conf = conf_dir + '/my.cnf'
if not os.path.exists(my_conf):
tpl = getPluginDir() + '/conf/my' + version + '.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(mysql_conf, content)
mw.writeFile(my_conf, content)
classic_conf = mode_dir + '/classic.cnf'
if not os.path.exists(classic_conf):
tpl = getPluginDir() + '/conf/classic.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(classic_conf, content)
gtid_conf = mode_dir + '/gtid.cnf'
if not os.path.exists(gtid_conf):
tpl = getPluginDir() + '/conf/gtid.cnf'
content = mw.readFile(tpl)
content = contentReplace(content)
mw.writeFile(gtid_conf, content)
# systemd
systemDir = mw.systemdCfgDir()
@@ -233,6 +261,13 @@ def binLog():
return mw.returnJson(True, '设置成功!')
def cleanBinLog():
db = pMysqlDb()
cleanTime = time.strftime('%Y-%m-%d %H:%i:%s', time.localtime())
db.execute("PURGE MASTER LOGS BEFORE '" + cleanTime + "';")
return mw.returnJson(True, '清理BINLOG成功!')
def setSkipGrantTables(v):
'''
设置是否密码验证
@@ -719,11 +754,13 @@ def importDbExternal():
mysql_cmd = getServerDir() + '/bin/usr/bin/mysql -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
# print(mysql_cmd)
os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if ext != 'sql':
os.remove(import_sql)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -748,8 +785,10 @@ def importDbBackup():
mysql_cmd = getServerDir() + '/bin/usr/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + name + ' < ' + file_path_sql
# print(mysql_cmd)
os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -1079,7 +1118,7 @@ def addDb():
dataAccess = args['dataAccess'].strip()
ps = args['ps'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, args['name']):
return mw.returnJson(False, '数据库名称不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1747,7 +1786,7 @@ def addMasterRepSlaveUser(version=''):
# address = args['address'].strip()
# dataAccess = args['dataAccess'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, username):
return mw.returnJson(False, '用户名不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1775,17 +1814,18 @@ def addMasterRepSlaveUser(version=''):
if isError != None:
return isError
sql = "FLUSH PRIVILEGES;"
pdb.execute(sql)
else:
sql = "GRANT REPLICATION SLAVE ON *.* TO '" + username + \
"'@'%' identified by '" + password + "';"
result = pdb.execute(sql)
result = pdb.execute('FLUSH PRIVILEGES;')
isError = isSqlError(result)
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
psdb.add('username,password,accept,ps,addtime',
(username, password, '%', '', addTime))
@@ -1922,6 +1962,123 @@ def getSlaveSSHList(version=''):
return mw.getJson(data)
def getSlaveSyncUserByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').where(
"ip=?", (ip,)).select()
return mw.returnJson(True, 'ok', data)
def addSlaveSyncUser(version=''):
import base64
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
if ip == "":
return mw.returnJson(True, 'ok')
data = checkArgs(args, ['port', 'user', 'pass', 'mode'])
if not data[0]:
return data[1]
cmd = args['cmd']
port = args['port']
user = args['user']
apass = args['pass']
mode = args['mode']
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip').where("ip=?", (ip,)).select()
if len(data) > 0:
res = conn.where("ip=?", (ip,)).save(
'port,user,pass,mode,cmd', (port, user, apass, mode, cmd))
else:
conn.add('ip,port,user,cmd,user,pass,mode,addtime',
(ip, port, user, cmd, user, apass, mode, addTime))
return mw.returnJson(True, '设置成功!')
def delSlaveSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
conn.where("ip=?", (ip,)).delete()
return mw.returnJson(True, '删除成功!')
def getSlaveSyncUserList(version=''):
args = getArgs()
data = checkArgs(args, ['page', 'page_size'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
conn = pSqliteDb('slave_sync_user')
limit = str((page - 1) * page_size) + ',' + str(page_size)
field = 'id,ip,port,user,pass,cmd,addtime'
clist = conn.field(field).limit(limit).order('id desc').select()
count = conn.count()
data = {}
_page = {}
_page['count'] = count
_page['p'] = page
_page['row'] = page_size
_page['tojs'] = args['tojs']
data['page'] = mw.getPage(_page)
data['data'] = clist
return mw.getJson(data)
def getSyncModeFile():
return getServerDir() + "/sync.mode"
def getSlaveSyncMode(version):
sync_mode = getSyncModeFile()
if os.path.exists(sync_mode):
mode = mw.readFile(sync_mode).strip()
return mw.returnJson(True, 'ok', mode)
return mw.returnJson(False, 'fail')
def setSlaveSyncMode(version):
args = getArgs()
data = checkArgs(args, ['mode'])
if not data[0]:
return data[1]
mode = args['mode']
sync_mode = getSyncModeFile()
if mode == 'none':
os.remove(sync_mode)
else:
mw.writeFile(sync_mode, mode)
return mw.returnJson(True, '设置成功', mode)
def getSlaveSSHByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
@@ -2024,6 +2181,47 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return initSlaveStatusSSH(version)
if mode == 'sync-user':
return initSlaveStatusSyncUser(version)
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
if len(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'
local_mode = recognizeDbMode()
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
t = db.query(u['cmd'])
# print(t)
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
def initSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) > 0:
@@ -2092,6 +2290,41 @@ def initSlaveStatus(version=''):
def setSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
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')
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']
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')
@@ -2160,6 +2393,68 @@ def writeDbSyncStatus(data):
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return doFullSyncSSH(version)
if mode == 'sync-user':
return doFullSyncUser(version)
def doFullSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
sync_db = args['db']
db = pMysqlDb()
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
bak_file = '/tmp/tmp.sql'
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
mode = recognizeDbMode()
if mode == 'gtid':
dmp_option = ' --set-gtid-purged=off '
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 + " " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
mw.execShell(my_import_cmd)
if version == '8.0':
db.query("start slave user='{}' password='{}';".format(user, apass))
else:
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + bak_file)
return True
def doFullSyncSSH(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
@@ -2485,6 +2780,18 @@ if __name__ == "__main__":
print(delSlaveSSH(version))
elif func == 'update_slave_ssh':
print(updateSlaveSSH(version))
elif func == 'get_slave_sync_user_list':
print(getSlaveSyncUserList(version))
elif func == 'get_slave_sync_user_by_ip':
print(getSlaveSyncUserByIp(version))
elif func == 'add_slave_sync_user':
print(addSlaveSyncUser(version))
elif func == 'del_slave_sync_user':
print(delSlaveSyncUser(version))
elif func == 'get_slave_sync_mode':
print(getSlaveSyncMode(version))
elif func == 'set_slave_sync_mode':
print(setSlaveSyncMode(version))
elif func == 'init_slave_status':
print(initSlaveStatus(version))
elif func == 'set_slave_status':
+1 -1
View File
@@ -4,7 +4,7 @@
"tip":"soft",
"name":"mysql-yum",
"type":"运行环境",
"ps":"[<b style='color:red;'>潜龙勿用</b>]一种关系数据库管理系统[centos](极速安装)",
"ps":"一种关系数据库管理系统[centos](极速安装)",
"todo_versions":["5.7","8.0"],
"versions":["5.7","8.0"],
"shell":"install.sh",
+278 -17
View File
@@ -265,7 +265,7 @@ function myPerfOpt() {
}
function reBootMySqld(){
pluginOpService('mysql-apt','restart','');
pluginOpService('mysql-yum','restart','');
}
@@ -731,7 +731,7 @@ function addDatabase(type){
layer.close(index);
dbList();
}
},{icon: rdata.status ? 1 : 2},600);
},{icon: rdata.status ? 1 : 2}, 2000);
});
}
});
@@ -818,7 +818,7 @@ function openPhpmyadmin(name,username,password){
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_cfg'});
var rdata = $.parseJSON(data.data);
if (rdata.choose != 'mysql-apt'){
if (rdata.choose != 'mysql-yum'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
return;
}
@@ -1207,7 +1207,7 @@ function myLogs(){
var limitCon = '<p class="conf_p">\
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;">清理日志</button></p>\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
@@ -1545,13 +1545,9 @@ function getMasterRepSlaveUserCmd(username, db=''){
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(){
showMsg(rdata.msg, function(){
getMasterRepSlaveList();
},1000);
},{icon: rdata.status ? 1 : 2},1000)
});
}
@@ -1821,8 +1817,23 @@ function addSlaveSSH(ip=''){
function delSlaveSSH(ip){
myPost('del_slave_ssh', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
getSlaveSSHPage();
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSSHPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
function delSlaveSyncUser(ip){
myPost('del_slave_sync_user', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
@@ -1872,6 +1883,237 @@ function getSlaveSSHPage(page=1){
}
function addSlaveSyncUser(ip=''){
myPost('get_slave_sync_user_by_ip', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var ip = '127.0.0.1';
var port = "22";
var cmd = '';
var user = 'input_sync_user';
var pass = 'input_sync_pwd';
var mode = '0';
if (rdata.data.length>0){
ip = rdata.data[0]['ip'];
port = rdata.data[0]['port'];
cmd = rdata.data[0]['cmd'];
user = rdata.data[0]['user'];
pass = rdata.data[0]['pass'];
mode = rdata.data[0]['mode'];
}
var index = layer.open({
type: 1,
area: ['500px','470px'],
title: '同步账户',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:["确认","取消"],
content: "<form class='bt-form pd20'>\
<div class='line'><span class='tname'>IP</span><div class='info-r'><input name='ip' class='bt-input-text mr5' type='text' style='width:330px;' value='"+ip+"'></div></div>\
<div class='line'><span class='tname'>端口</span><div class='info-r'><input name='port' class='bt-input-text mr5' type='number' style='width:330px;' value='"+port+"'></div></div>\
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
<div class='line'>\
<span class='tname'>CMD[最好填好]</span>\
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
</div>\
<input type='hidden' name='mode' value='"+mode+"' />\
</form>",
success:function(){
$('textarea[name="cmd"]').html(cmd);
$('textarea[name="cmd"]').change(function(){
var val = $(this).val();
var vlist = val.split(',');
var a = {};
for (var i in vlist) {
var tmp = toTrim(vlist[i]);
var tmp_a = tmp.split(" ");
var real_tmp = tmp_a[tmp_a.length-1];
var kv = real_tmp.split("=");
a[kv[0]] = kv[1].replace("'",'').replace("'",'');
}
$('input[name="ip"]').val(a['MASTER_HOST']);
$('input[name="port"]').val(a['MASTER_PORT']);
$('input[name="user"]').val(a['MASTER_USER']);
$('input[name="pass"]').val(a['MASTER_PASSWORD']);
console.log(a['MASTER_AUTO_POSITION'],typeof(a['MASTER_AUTO_POSITION']));
if (typeof(a['MASTER_AUTO_POSITION']) != 'undefined' ){
$('input[name="mode"]').val('1');
}
});
},
yes:function(index){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var user = $('input[name="user"]').val();
var pass = $('input[name="pass"]').val();
var cmd = $('textarea[name="cmd"]').val();
var mode = $('input[name="mode"]').val();
var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
myPost('add_slave_sync_user', data, function(ret_data){
layer.close(index);
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2},600);
});
}
});
});
}
function getSlaveSyncUserPage(page=1){
var _data = {};
_data['page'] = page;
_data['page_size'] = 5;
_data['tojs'] ='getSlaveSyncUserPage';
myPost('get_slave_sync_user_list', _data, function(data){
var layerId = null;
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e) {
console.log(e);
}
var list = '';
var user_list = rdata['data'];
for (i in user_list) {
var ip = user_list[i]['ip'];
var port = user_list[i]['port'];
var user = user_list[i]['user'];
var apass = user_list[i]['pass'];
var cmd = '未设置';
if (user_list[i]['cmd']!=''){
cmd = '已设置';
}
list += '<tr><td>'+ip+'</td>\
<td>'+port+'</td>\
<td>'+user+'</td>\
<td>'+apass+'</td>\
<td>'+cmd+'</td>\
<td>\
<a class="btlink" onclick="addSlaveSyncUser(\''+ip+'\');">修改</a> | \
<a class="btlink" onclick="delSlaveSyncUser(\''+ip+'\');">删除</a>\
</td>\
</tr>';
}
$('.get-slave-ssh-list tbody').html(list);
$('.dataTables_paginate_4').html(rdata['page']);
});
}
function getSlaveCfg(){
myPost('get_slave_sync_mode', '', function(data){
var rdata = $.parseJSON(data.data);
var mode_none = 'success';
var mode_ssh = 'danger';
var mode_sync_user = 'danger';
if(rdata.status){
var mode_none = 'danger';
if (rdata.data == 'ssh'){
var mode_ssh = 'success';
var mode_sync_user = 'danger';
} else {
var mode_ssh = 'danger';
var mode_sync_user = 'success';
}
}
layerId = layer.open({
type: 1,
title: '同步配置',
area: ['400px','180px'],
content:"<div class='bt-form pd20 c6'>\
<p class='conf_p'>\
<span class='f14 c6 mr20'>当前从库同步模式</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-"+mode_none+" btn-xs slave-db-mode btn-none'>无</button>\
<button class='btn btn-"+mode_ssh+" btn-xs slave-db-mode btn-ssh'>SSH</button>\
<button class='btn btn-"+mode_sync_user+" btn-xs slave-db-mode btn-sync-user'>同步账户</button>\
</p>\
<hr />\
<p class='conf_p'>\
<span class='f14 c6 mr20'>配置设置</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-success btn-xs btn-slave-ssh'>SSH</button>\
<button class='btn btn-success btn-xs btn-slave-user'>同步账户</button>\
</p>\
</div>",
success:function(){
$('.btn-slave-ssh').click(function(){
getSlaveSSHList();
});
$('.btn-slave-user').click(function(){
getSlaveUserList();
});
$('.slave-db-mode').click(function(){
var _this = this;
var mode = 'none';
if ($(this).hasClass('btn-ssh')){
mode = 'ssh';
}
if ($(this).hasClass('btn-sync-user')){
mode = 'sync-user';
}
myPost('set_slave_sync_mode', {mode:mode}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
$('.slave-db-mode').remove('btn-success').addClass('btn-danger');
$(_this).removeClass('btn-danger').addClass('btn-success');
},{icon:rdata.status?1:2},2000);
});
});
}
});
});
}
function getSlaveUserList(){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
page += '<div class="table_toolbar" style="left:0px;"><span class="sync btn btn-default btn-sm" onclick="addSlaveSyncUser()" title="">添加同步账户</span></div>';
layerId = layer.open({
type: 1,
title: '同步账户列表',
area: '500px',
content:"<div class='bt-form pd20 c6'>\
<div class='divtable mtb10'>\
<div><table class='table table-hover get-slave-ssh-list'>\
<thead><tr><th>IP</th><th>PORT</th><th>同步账户</th><th>同步密码</th><th>CMD</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table></div>\
"+page +"\
</div>\
</div>",
success:function(){
getSlaveSyncUserPage(1);
}
});
}
function getSlaveSSHList(page=1){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
@@ -1991,7 +2233,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
var status = "异常";
var status = "<a class='btlink db_error'>异常</>";
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
status = "正常";
}
@@ -2033,6 +2275,26 @@ function masterOrSlaveConf(version=''){
// <span class="sync btn btn-default btn-sm" onclick="getMasterRepSlaveList()" title="">添加</span>\
// </div>
$(".table_slave_status_list").html(con);
$('.db_error').click(function(){
layer.open({
type: 1,
title: '同步异常信息',
area: '500px',
content:"<form class='bt-form pd20 pb70'>\
<div class='line'>"+v['Error']+"</div>\
<div class='bt-form-submit-btn'>\
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
</div>\
</form>",
success:function(){
copyText(v['Error']);
$('.class-copy-db-err').click(function(){
copyText(v['Error']);
});
}
});
});
});
}
@@ -2079,7 +2341,6 @@ function masterOrSlaveConf(version=''){
});
}
function getMasterStatus(){
myPost('get_master_status', '', function(rdata){
@@ -2110,7 +2371,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Slave[从]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.slave_status ? 'btn-danger' : 'btn-success')+' btn-xs btn-slave">'+(!rdata.slave_status ? '未启动' : '已启动') +'</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveSSHList()" >[主]SSH配置</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveCfg()" >同步配置</button>\
<button class="btn btn-success btn-xs" onclick="initSlaveStatus()" >初始化</button>\
</p>\
<hr/>\
@@ -2184,10 +2445,10 @@ function masterOrSlaveConf(version=''){
getMasterDbList();
}
if (rdata.slave_status){
// if (rdata.slave_status){
getAsyncMasterDbList();
getAsyncDataList()
}
// }
});
}
getMasterStatus();
+2 -1
View File
@@ -67,7 +67,8 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates = 1
skip-slave-start = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
+2 -1
View File
@@ -69,7 +69,8 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates = 1
skip-slave-start = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
+5 -5
View File
@@ -8,9 +8,6 @@ default-character-set = UTF8MB4
[mysqld]
!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
;sha256_password_private_key_path=mysql.pem
;sha256_password_public_key_path=mysql.pub
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 3306
@@ -44,6 +41,7 @@ open_files_limit = 2560
max_allowed_packet = 128M
skip_name_resolve = 1
skip-ssl
#skip-networking
#skip-external-locking
#loose-skip-innodb
@@ -70,8 +68,10 @@ binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#slave
log-slave-updates = 1
skip-slave-start = 1
# 5.7 It can not be opened later
#log-slave-updates = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
+2 -1
View File
@@ -68,7 +68,8 @@ binlog-ignore-db = performance_schema
#slave
log_replica_updates = 1
skip_replica_start = 1
# Prevent replication from starting automatically with MySQL
#skip_replica_start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
+13
View File
@@ -40,4 +40,17 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`addtime` TEXT
);
-- 从库配置主库的[user]
-- drop table `slave_user`;
CREATE TABLE IF NOT EXISTS `slave_sync_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`ip` TEXT,
`port` TEXT,
`user` TEXT,
`pass` TEXT,
`mode` TEXT,
`cmd` TEXT,
`addtime` TEXT
);
+1 -1
View File
@@ -53,7 +53,7 @@
.conf_p span {
display: inline-block;
margin-right: 10px;
width: 135px;
width: 115px;
text-align: right;
}
</style>
+328 -23
View File
@@ -127,20 +127,27 @@ def contentReplace(content):
def pSqliteDb(dbname='databases'):
file = getServerDir() + '/mysql.db'
name = 'mysql'
if not os.path.exists(file):
import_sql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
md5_sql = mw.md5(import_sql)
import_sign = False
save_md5_file = getServerDir() + '/import_sql.md5'
if os.path.exists(save_md5_file):
save_md5_sql = mw.readFile(save_md5_file)
if save_md5_sql != md5_sql:
import_sign = True
mw.writeFile(save_md5_file, md5_sql)
else:
mw.writeFile(save_md5_file, md5_sql)
if not os.path.exists(file) or import_sql:
conn = mw.M(dbname).dbPos(getServerDir(), name)
csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
csql_list = csql.split(';')
csql_list = import_sql.split(';')
for index in range(len(csql_list)):
conn.execute(csql_list[index], ())
else:
# 现有run
# conn = mw.M(dbname).dbPos(getServerDir(), name)
# csql = mw.readFile(getPluginDir() + '/conf/mysql.sql')
# csql_list = csql.split(';')
# for index in range(len(csql_list)):
# conn.execute(csql_list[index], ())
conn = mw.M(dbname).dbPos(getServerDir(), name)
conn = mw.M(dbname).dbPos(getServerDir(), name)
return conn
@@ -899,11 +906,13 @@ def importDbExternal():
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
# print(mysql_cmd)
os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if ext != 'sql':
os.remove(import_sql)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -923,13 +932,23 @@ def importDbBackup():
cmd = 'cd ' + mw.getRootDir() + '/backup/database && gzip -d ' + file
mw.execShell(cmd)
local_mode = recognizeDbMode()
if local_mode == 'gtid':
pdb = pMysqlDb()
pdb.execute('reset master')
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + name + ' < ' + file_path_sql
# print(mysql_cmd)
os.system(mysql_cmd)
# os.system(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
if rdata[1].lower().find('error') > -1:
return mw.returnJson(False, rdata[1])
return mw.returnJson(True, 'ok')
@@ -1260,7 +1279,7 @@ def addDb():
dataAccess = args['dataAccess'].strip()
ps = args['ps'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, args['name']):
return mw.returnJson(False, '数据库名称不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1928,7 +1947,7 @@ def addMasterRepSlaveUser(version=''):
# address = args['address'].strip()
# dataAccess = args['dataAccess'].strip()
reg = "^[\w\.-]+$"
reg = "^[\w-]+$"
if not re.match(reg, username):
return mw.returnJson(False, '用户名不能带有特殊符号!')
checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
@@ -1956,17 +1975,18 @@ def addMasterRepSlaveUser(version=''):
if isError != None:
return isError
sql = "FLUSH PRIVILEGES;"
pdb.execute(sql)
else:
sql = "GRANT REPLICATION SLAVE ON *.* TO '" + username + \
sql = "grant replication SLAVE ON *.* TO '" + username + \
"'@'%' identified by '" + password + "';"
result = pdb.execute(sql)
result = pdb.execute('FLUSH PRIVILEGES;')
isError = isSqlError(result)
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
psdb.add('username,password,accept,ps,addtime',
(username, password, '%', '', addTime))
@@ -2103,6 +2123,123 @@ def getSlaveSSHList(version=''):
return mw.getJson(data)
def getSlaveSyncUserByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').where(
"ip=?", (ip,)).select()
return mw.returnJson(True, 'ok', data)
def addSlaveSyncUser(version=''):
import base64
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
if ip == "":
return mw.returnJson(True, 'ok')
data = checkArgs(args, ['port', 'user', 'pass', 'mode'])
if not data[0]:
return data[1]
cmd = args['cmd']
port = args['port']
user = args['user']
apass = args['pass']
mode = args['mode']
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip').where("ip=?", (ip,)).select()
if len(data) > 0:
res = conn.where("ip=?", (ip,)).save(
'port,user,pass,mode,cmd', (port, user, apass, mode, cmd))
else:
conn.add('ip,port,user,cmd,user,pass,mode,addtime',
(ip, port, user, cmd, user, apass, mode, addTime))
return mw.returnJson(True, '设置成功!')
def delSlaveSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
if not data[0]:
return data[1]
ip = args['ip']
conn = pSqliteDb('slave_sync_user')
conn.where("ip=?", (ip,)).delete()
return mw.returnJson(True, '删除成功!')
def getSlaveSyncUserList(version=''):
args = getArgs()
data = checkArgs(args, ['page', 'page_size'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
conn = pSqliteDb('slave_sync_user')
limit = str((page - 1) * page_size) + ',' + str(page_size)
field = 'id,ip,port,user,pass,cmd,addtime'
clist = conn.field(field).limit(limit).order('id desc').select()
count = conn.count()
data = {}
_page = {}
_page['count'] = count
_page['p'] = page
_page['row'] = page_size
_page['tojs'] = args['tojs']
data['page'] = mw.getPage(_page)
data['data'] = clist
return mw.getJson(data)
def getSyncModeFile():
return getServerDir() + "/sync.mode"
def getSlaveSyncMode(version):
sync_mode = getSyncModeFile()
if os.path.exists(sync_mode):
mode = mw.readFile(sync_mode).strip()
return mw.returnJson(True, 'ok', mode)
return mw.returnJson(False, 'fail')
def setSlaveSyncMode(version):
args = getArgs()
data = checkArgs(args, ['mode'])
if not data[0]:
return data[1]
mode = args['mode']
sync_mode = getSyncModeFile()
if mode == 'none':
os.remove(sync_mode)
else:
mw.writeFile(sync_mode, mode)
return mw.returnJson(True, '设置成功', mode)
def getSlaveSSHByIp(version=''):
args = getArgs()
data = checkArgs(args, ['ip'])
@@ -2160,7 +2297,7 @@ def delSlaveSSH(version=''):
conn = pSqliteDb('slave_id_rsa')
conn.where("ip=?", (ip,)).delete()
return mw.returnJson(True, 'ok')
return mw.returnJson(True, '删除SSH成功!')
def updateSlaveSSH(version=''):
@@ -2189,6 +2326,24 @@ def getSlaveList(version=''):
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"]
tmp['Last_Error'] = dlist[x]["Last_Error"]
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
tmp['Error'] = ''
if tmp['Last_Error'] != '':
tmp['Error'] = tmp['Last_Error']
if tmp['Last_IO_Error'] != '':
tmp['Error'] = tmp['Last_IO_Error']
if tmp['Last_SQL_Error'] != '':
tmp['Error'] = tmp['Last_SQL_Error']
if tmp['Error'] == '':
tmp['Error'] = tmp['Slave_SQL_Running_State']
ret.append(tmp)
data = {}
data['data'] = ret
@@ -2205,6 +2360,47 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return initSlaveStatusSSH(version)
if mode == 'sync-user':
return initSlaveStatusSyncUser(version)
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
if len(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'
local_mode = recognizeDbMode()
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
t = db.query(u['cmd'])
# print(t)
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
def initSlaveStatusSSH(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) > 0:
@@ -2214,7 +2410,7 @@ def initSlaveStatus(version=''):
data = conn.field('ip,port,id_rsa').find()
if len(data) < 1:
return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
return mw.returnJson(False, '需要先添加SSH配置!')
SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
ip = data['ip']
@@ -2273,11 +2469,46 @@ def initSlaveStatus(version=''):
def setSlaveStatus(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
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')
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']
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, '需要手动添加主服务命令或者执行[初始化]!')
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')
@@ -2342,6 +2573,68 @@ def writeDbSyncStatus(data):
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode == 'ssh':
return doFullSyncSSH(version)
if mode == 'sync-user':
return doFullSyncUser(version)
def doFullSyncUser(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
sync_db = args['db']
db = pMysqlDb()
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
bak_file = '/tmp/tmp.sql'
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
mode = recognizeDbMode()
if mode == 'gtid':
dmp_option = ' --set-gtid-purged=off '
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 + " " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
mw.execShell(my_import_cmd)
if version == '8.0':
db.query("start slave user='{}' password='{}';".format(user, apass))
else:
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + bak_file)
return True
def doFullSyncSSH(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
@@ -2653,6 +2946,18 @@ if __name__ == "__main__":
print(delSlaveSSH(version))
elif func == 'update_slave_ssh':
print(updateSlaveSSH(version))
elif func == 'get_slave_sync_user_list':
print(getSlaveSyncUserList(version))
elif func == 'get_slave_sync_user_by_ip':
print(getSlaveSyncUserByIp(version))
elif func == 'add_slave_sync_user':
print(addSlaveSyncUser(version))
elif func == 'del_slave_sync_user':
print(delSlaveSyncUser(version))
elif func == 'get_slave_sync_mode':
print(getSlaveSyncMode(version))
elif func == 'set_slave_sync_mode':
print(setSlaveSyncMode(version))
elif func == 'init_slave_status':
print(initSlaveStatus(version))
elif func == 'set_slave_status':
+275 -14
View File
@@ -731,7 +731,7 @@ function addDatabase(type){
layer.close(index);
dbList();
}
},{icon: rdata.status ? 1 : 2},600);
},{icon: rdata.status ? 1 : 2}, 2000);
});
}
});
@@ -1545,13 +1545,9 @@ function getMasterRepSlaveUserCmd(username, db=''){
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(){
showMsg(rdata.msg, function(){
getMasterRepSlaveList();
},1000);
},{icon: rdata.status ? 1 : 2},1000)
});
}
@@ -1821,8 +1817,23 @@ function addSlaveSSH(ip=''){
function delSlaveSSH(ip){
myPost('del_slave_ssh', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
getSlaveSSHPage();
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSSHPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
function delSlaveSyncUser(ip){
myPost('del_slave_sync_user', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2}, 600);
});
}
@@ -1872,6 +1883,237 @@ function getSlaveSSHPage(page=1){
}
function addSlaveSyncUser(ip=''){
myPost('get_slave_sync_user_by_ip', {ip:ip}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var ip = '127.0.0.1';
var port = "22";
var cmd = '';
var user = 'input_sync_user';
var pass = 'input_sync_pwd';
var mode = '0';
if (rdata.data.length>0){
ip = rdata.data[0]['ip'];
port = rdata.data[0]['port'];
cmd = rdata.data[0]['cmd'];
user = rdata.data[0]['user'];
pass = rdata.data[0]['pass'];
mode = rdata.data[0]['mode'];
}
var index = layer.open({
type: 1,
area: ['500px','470px'],
title: '同步账户',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:["确认","取消"],
content: "<form class='bt-form pd20'>\
<div class='line'><span class='tname'>IP</span><div class='info-r'><input name='ip' class='bt-input-text mr5' type='text' style='width:330px;' value='"+ip+"'></div></div>\
<div class='line'><span class='tname'>端口</span><div class='info-r'><input name='port' class='bt-input-text mr5' type='number' style='width:330px;' value='"+port+"'></div></div>\
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
<div class='line'>\
<span class='tname'>CMD[最好填好]</span>\
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
</div>\
<input type='hidden' name='mode' value='"+mode+"' />\
</form>",
success:function(){
$('textarea[name="cmd"]').html(cmd);
$('textarea[name="cmd"]').change(function(){
var val = $(this).val();
var vlist = val.split(',');
var a = {};
for (var i in vlist) {
var tmp = toTrim(vlist[i]);
var tmp_a = tmp.split(" ");
var real_tmp = tmp_a[tmp_a.length-1];
var kv = real_tmp.split("=");
a[kv[0]] = kv[1].replace("'",'').replace("'",'');
}
$('input[name="ip"]').val(a['MASTER_HOST']);
$('input[name="port"]').val(a['MASTER_PORT']);
$('input[name="user"]').val(a['MASTER_USER']);
$('input[name="pass"]').val(a['MASTER_PASSWORD']);
console.log(a['MASTER_AUTO_POSITION'],typeof(a['MASTER_AUTO_POSITION']));
if (typeof(a['MASTER_AUTO_POSITION']) != 'undefined' ){
$('input[name="mode"]').val('1');
}
});
},
yes:function(index){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var user = $('input[name="user"]').val();
var pass = $('input[name="pass"]').val();
var cmd = $('textarea[name="cmd"]').val();
var mode = $('input[name="mode"]').val();
var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
myPost('add_slave_sync_user', data, function(ret_data){
layer.close(index);
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
getSlaveSyncUserPage();
}
},{icon: rdata.status ? 1 : 2},600);
});
}
});
});
}
function getSlaveSyncUserPage(page=1){
var _data = {};
_data['page'] = page;
_data['page_size'] = 5;
_data['tojs'] ='getSlaveSyncUserPage';
myPost('get_slave_sync_user_list', _data, function(data){
var layerId = null;
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e) {
console.log(e);
}
var list = '';
var user_list = rdata['data'];
for (i in user_list) {
var ip = user_list[i]['ip'];
var port = user_list[i]['port'];
var user = user_list[i]['user'];
var apass = user_list[i]['pass'];
var cmd = '未设置';
if (user_list[i]['cmd']!=''){
cmd = '已设置';
}
list += '<tr><td>'+ip+'</td>\
<td>'+port+'</td>\
<td>'+user+'</td>\
<td>'+apass+'</td>\
<td>'+cmd+'</td>\
<td>\
<a class="btlink" onclick="addSlaveSyncUser(\''+ip+'\');">修改</a> | \
<a class="btlink" onclick="delSlaveSyncUser(\''+ip+'\');">删除</a>\
</td>\
</tr>';
}
$('.get-slave-ssh-list tbody').html(list);
$('.dataTables_paginate_4').html(rdata['page']);
});
}
function getSlaveCfg(){
myPost('get_slave_sync_mode', '', function(data){
var rdata = $.parseJSON(data.data);
var mode_none = 'success';
var mode_ssh = 'danger';
var mode_sync_user = 'danger';
if(rdata.status){
var mode_none = 'danger';
if (rdata.data == 'ssh'){
var mode_ssh = 'success';
var mode_sync_user = 'danger';
} else {
var mode_ssh = 'danger';
var mode_sync_user = 'success';
}
}
layerId = layer.open({
type: 1,
title: '同步配置',
area: ['400px','180px'],
content:"<div class='bt-form pd20 c6'>\
<p class='conf_p'>\
<span class='f14 c6 mr20'>当前从库同步模式</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-"+mode_none+" btn-xs slave-db-mode btn-none'>无</button>\
<button class='btn btn-"+mode_ssh+" btn-xs slave-db-mode btn-ssh'>SSH</button>\
<button class='btn btn-"+mode_sync_user+" btn-xs slave-db-mode btn-sync-user'>同步账户</button>\
</p>\
<hr />\
<p class='conf_p'>\
<span class='f14 c6 mr20'>配置设置</span>\
<b class='f14 c6 mr20'></b>\
<button class='btn btn-success btn-xs btn-slave-ssh'>SSH</button>\
<button class='btn btn-success btn-xs btn-slave-user'>同步账户</button>\
</p>\
</div>",
success:function(){
$('.btn-slave-ssh').click(function(){
getSlaveSSHList();
});
$('.btn-slave-user').click(function(){
getSlaveUserList();
});
$('.slave-db-mode').click(function(){
var _this = this;
var mode = 'none';
if ($(this).hasClass('btn-ssh')){
mode = 'ssh';
}
if ($(this).hasClass('btn-sync-user')){
mode = 'sync-user';
}
myPost('set_slave_sync_mode', {mode:mode}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
$('.slave-db-mode').remove('btn-success').addClass('btn-danger');
$(_this).removeClass('btn-danger').addClass('btn-success');
},{icon:rdata.status?1:2},2000);
});
});
}
});
});
}
function getSlaveUserList(){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
page += '<div class="table_toolbar" style="left:0px;"><span class="sync btn btn-default btn-sm" onclick="addSlaveSyncUser()" title="">添加同步账户</span></div>';
layerId = layer.open({
type: 1,
title: '同步账户列表',
area: '500px',
content:"<div class='bt-form pd20 c6'>\
<div class='divtable mtb10'>\
<div><table class='table table-hover get-slave-ssh-list'>\
<thead><tr><th>IP</th><th>PORT</th><th>同步账户</th><th>同步密码</th><th>CMD</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table></div>\
"+page +"\
</div>\
</div>",
success:function(){
getSlaveSyncUserPage(1);
}
});
}
function getSlaveSSHList(page=1){
var page = '<div class="dataTables_paginate_4 dataTables_paginate paging_bootstrap page" style="margin-top:0px;"></div>';
@@ -1991,7 +2233,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
var status = "异常";
var status = "<a class='btlink db_error'>异常</>";
if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
status = "正常";
}
@@ -2033,6 +2275,26 @@ function masterOrSlaveConf(version=''){
// <span class="sync btn btn-default btn-sm" onclick="getMasterRepSlaveList()" title="">添加</span>\
// </div>
$(".table_slave_status_list").html(con);
$('.db_error').click(function(){
layer.open({
type: 1,
title: '同步异常信息',
area: '500px',
content:"<form class='bt-form pd20 pb70'>\
<div class='line'>"+v['Error']+"</div>\
<div class='bt-form-submit-btn'>\
<button type='button' class='btn btn-success btn-sm btn-title class-copy-db-err'>复制</button>\
</div>\
</form>",
success:function(){
copyText(v['Error']);
$('.class-copy-db-err').click(function(){
copyText(v['Error']);
});
}
});
});
});
}
@@ -2079,7 +2341,6 @@ function masterOrSlaveConf(version=''){
});
}
function getMasterStatus(){
myPost('get_master_status', '', function(rdata){
@@ -2110,7 +2371,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Slave[从]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.slave_status ? 'btn-danger' : 'btn-success')+' btn-xs btn-slave">'+(!rdata.slave_status ? '未启动' : '已启动') +'</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveSSHList()" >[主]SSH配置</button>\
<button class="btn btn-success btn-xs" onclick="getSlaveCfg()" >同步配置</button>\
<button class="btn btn-success btn-xs" onclick="initSlaveStatus()" >初始化</button>\
</p>\
<hr/>\
@@ -2184,10 +2445,10 @@ function masterOrSlaveConf(version=''){
getMasterDbList();
}
if (rdata.slave_status){
// if (rdata.slave_status){
getAsyncMasterDbList();
getAsyncDataList()
}
// }
});
}
getMasterStatus();
+1
View File
@@ -61,6 +61,7 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php/${type} ];then
# cd /www/server/mdserver-web/plugins/php/versions/common && bash iconv.sh install 53
# cd /www/server/mdserver-web/plugins/php/versions/common && bash gd.sh install 56
# cd /www/server/mdserver-web/plugins/php/versions/common && bash openssl.sh install 56
# cd /www/server/mdserver-web/plugins/php/versions/common && bash sodium.sh install 81
cd ${rootPath}/plugins/php/versions/common && bash gd.sh install ${type}
cd ${rootPath}/plugins/php/versions/common && bash iconv.sh install ${type}
cd ${rootPath}/plugins/php/versions/common && bash exif.sh install ${type}
+2 -2
View File
@@ -16,7 +16,7 @@ SOURCE_ROOT=$rootPath/source/lib
VERSION=1.0.18
#----------------------------- libsodium start -------------------------#
if [ ! -d ${SERVER_ROOT}/libsodium-stable ];then
if [ ! -f /usr/local/lib/libsodium.so ];then
cd ${SOURCE_ROOT}
if [ ! -f ${SOURCE_ROOT}/libsodium-${VERSION}-stable.tar.gz ];then
# wget --no-check-certificate -O libsodium-1.0.18-stable.tar.gz https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable.tar.gz -T 20
@@ -24,6 +24,6 @@ if [ ! -d ${SERVER_ROOT}/libsodium-stable ];then
fi
tar -zxvf libsodium-${VERSION}-stable.tar.gz
cd libsodium-stable
./configure --prefix=${SERVER_ROOT}/libsodium && make && make check && sudo make install
./configure && make && make check && sudo make install
fi
#----------------------------- libsodium end -------------------------#
+2 -1
View File
@@ -106,7 +106,8 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then
$OPTIONS \
--enable-fastcgi \
--enable-fpm
make ZEND_EXTRA_LIBS='-liconv' && make install && make clean
# ZEND_EXTRA_LIBS='-liconv'
make && make install && make clean
fi
if [ "$?" != "0" ];then
+3 -2
View File
@@ -47,8 +47,9 @@ Install_lib()
cd $php_lib && tar xvf ${LIBNAME}-${LIBV}.tgz
cd ${LIBNAME}-${LIBV}
$serverPath/php/$version/bin/phpize
./configure --with-php-config=$serverPath/php/$version/bin/php-config \
--with-icu-dir=${serverPath}/lib/icu
# --with-icu-dir=${serverPath}/lib/icu
./configure --with-php-config=$serverPath/php/$version/bin/php-config
make clean && make && make install && make clean
fi
+115
View File
@@ -0,0 +1,115 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
appPath=$(dirname "$curPath")
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sourcePath=${serverPath}/source/php
actionType=$1
version=$2
LIBNAME=gmp
LIBV=0
if [ "$version" == "53" ];then
echo "i wont support it"
exit
fi
LIB_PATH_NAME=lib/php
if [ -d $serverPath/php/${version}/lib64 ];then
LIB_PATH_NAME=lib64
fi
NON_ZTS_FILENAME=`ls $serverPath/php/${version}/${LIB_PATH_NAME}/extensions | grep no-debug-non-zts`
extFile=$serverPath/php/${version}/${LIB_PATH_NAME}/extensions/${NON_ZTS_FILENAME}/${LIBNAME}.so
sysName=`uname`
if [ "$sysName" == "Darwin" ];then
BAK='_bak'
else
BAK=''
fi
Install_lib()
{
isInstall=`cat $serverPath/php/$version/etc/php.ini|grep "${LIBNAME}.so"`
if [ "${isInstall}" != "" ];then
echo "php-$version 已安装${LIBNAME},请选择其它版本!"
return
fi
if [ ! -f "$extFile" ];then
if [ ! -d $sourcePath/php${version}/ext ];then
cd ${rootPath}/plugins/php && /bin/bash install.sh install ${version}
fi
cd $sourcePath/php${version}/ext/${LIBNAME}
$serverPath/php/$version/bin/phpize
./configure --with-php-config=$serverPath/php/$version/bin/php-config
# FIND_C99=`cat Makefile|grep c99`
# if [ "$FIND_C99" == "" ];then
# sed -i $BAK 's/CFLAGS \=/CFLAGS \= -std=c99/g' Makefile
# fi
make clean && make && make install && make clean
fi
if [ ! -f "$extFile" ];then
echo "ERROR!"
return
fi
echo "" >> $serverPath/php/$version/etc/php.ini
echo "[${LIBNAME}]" >> $serverPath/php/$version/etc/php.ini
echo "extension=${LIBNAME}.so" >> $serverPath/php/$version/etc/php.ini
bash ${rootPath}/plugins/php/versions/lib.sh $version restart
echo '==========================================================='
echo 'successful!'
}
Uninstall_lib()
{
if [ ! -f "$serverPath/php/$version/bin/php-config" ];then
echo "php-$version 未安装,请选择其它版本!"
return
fi
if [ ! -f "$extFile" ];then
echo "php-$version 未安装${LIBNAME},请选择其它版本!"
return
fi
echo $serverPath/php/$version/etc/php.ini
sed -i $BAK "/${LIBNAME}.so/d" $serverPath/php/$version/etc/php.ini
sed -i $BAK "/${LIBNAME}/d" $serverPath/php/$version/etc/php.ini
rm -f $extFile
bash ${rootPath}/plugins/php/versions/lib.sh $version restart
echo '==============================================='
echo 'successful!'
}
if [ "$actionType" == 'install' ];then
Install_lib
elif [ "$actionType" == 'uninstall' ];then
Uninstall_lib
fi
+1 -1
View File
@@ -53,7 +53,7 @@ Install_lib()
wget -O $php_lib/${LIBNAME}-${LIBV}.tgz http://pecl.php.net/get/lib${LIBNAME}-${LIBV}.tgz
cd $php_lib && tar xvf ${LIBNAME}-${LIBV}.tgz
fi
cd $php_lib/${LIBNAME}-${LIBV}
cd $php_lib/lib${LIBNAME}-${LIBV}
$serverPath/php/$version/bin/phpize
./configure --with-php-config=$serverPath/php/$version/bin/php-config --with-sodium=$serverPath/lib/libsodium
+17
View File
@@ -79,6 +79,23 @@
"shell": "sodium.sh",
"check": "sodium.so"
},
{
"name": "gmp",
"versions": [
"70",
"71",
"72",
"73",
"74",
"80",
"81",
"82"
],
"type": "运算库",
"msg": "一个开源的数学运算库",
"shell": "gmp.sh",
"check": "gmp.so"
},
{
"name": "opcache",
"versions": [
+1
View File
@@ -17,6 +17,7 @@ AntiWarez yes
Bind 0.0.0.0,21
Umask 133:022
MinUID 100
PassivePortRange 39000 40000
AllowUserFXP no
AllowAnonymousFXP no
ProhibitDotFilesWrite no
+17
View File
@@ -81,6 +81,22 @@ def contentReplace(content):
return content
def ftp_release_port(port):
from collections import namedtuple
try:
import firewall_api
firewall_api.firewall_api().addAcceptPortArgs(port, 'pure-ftpd', 'port')
return port
except Exception as e:
return "Release failed {}".format(e)
def openFtpPort():
for i in ["21", "39000:40000"]:
ftp_release_port(i)
return True
def initDreplace():
file_tpl = getInitDTpl()
@@ -89,6 +105,7 @@ def initDreplace():
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
openFtpPort()
file_bin = initD_path + '/' + getPluginName()
# initd replace
+2 -2
View File
@@ -53,8 +53,8 @@ Install_pureftp()
# curl -sSLo pure-ftpd-1.0.49.tar.gz https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.49.tar.gz
if [ ! -f $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz ];then
wget --no-check-certificate -O $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
# curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
# wget --no-check-certificate -O $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
curl -sSLo $serverPath/source/pureftp/pure-ftpd-${VER}.tar.gz $DOWNLOAD
fi
#检测文件是否损坏.
+4
View File
@@ -108,6 +108,10 @@ Install_App()
echo '安装完成' > $install_tmp
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py start
# delete install data
rm -rf $serverPath/source/webstats
}
Uninstall_App()
+2 -2
View File
@@ -1,6 +1,6 @@
setuptools>=33.1.1
Werkzeug>=1.0.1
wheel==0.33.6
wheel==0.37.1
gunicorn==20.1.0
requests==2.27.1
urllib3>=1.21.1
@@ -27,4 +27,4 @@ Jinja2>=2.11.2
flask-caching>=1.10.1
bcrypt==3.1.3
PyMySQL==1.0.2
whitenoise==5.3.0
whitenoise==5.3.0
+10 -1
View File
@@ -223,9 +223,18 @@ def publicObject(toObject, func, action=None, get=None):
# print(os)
# return mw.getLocalIp()
# 仅针对webhook插件
@app.route("/.well-known/acme-challenge/<val>")
def wellknow(val=None):
# 申请面板ssl使用
f = mw.getRunDir() + "/tmp/.well-known/acme-challenge/" + val
if os.path.exists(f):
return mw.readFile(f)
return ''
@app.route("/hook")
def webhook():
# 仅针对webhook插件
input_args = {
'access_key': request.args.get('access_key', '').strip(),
'params': request.args.get('params', '').strip()
+44 -21
View File
@@ -364,11 +364,11 @@ function getPanelSSL(){
var cert_data = '';
if (cert['info']){
cert_data = "<div class='ssl_state_info'><div class='state_info_flex'>\
<div class='state_item'><span>证书品牌:</span><span class='ellipsis_text'>"+cert['info']['issuer']+"</span></div>\
<div class='state_item'><span>到期时间:</span><span class='btlink'>剩余"+cert['info']['endtime']+"天到期</span></div>\
<div class='state_item'><span>证书品牌:</span><span class='ellipsis_text ssl_issue'>"+cert['info']['issuer']+"</span></div>\
<div class='state_item'><span>到期时间:</span><span class='btlink ssl_endtime'>剩余"+cert['info']['endtime']+"天到期</span></div>\
</div>\
<div class='state_info_flex'>\
<div class='state_item'><span>认证域名:</span><span class='ellipsis_text'>"+cert['info']['subject']+"</span></div>\
<div class='state_item'><span>认证域名:</span><span class='ellipsis_text ssl_subject'>"+cert['info']['subject']+"</span></div>\
</div></div>";
}
@@ -384,7 +384,8 @@ function getPanelSSL(){
</div>\
</div>\
<div class="ssl-btn pull-left mtb15" style="width:100%">\
<button class="btn btn-success btn-sm" onclick="savePanelSSL()">保存</button>\
<button class="btn btn-success btn-sm save-panel-ssl">保存</button>\
<button class="btn btn-success btn-sm apply-lets-ssl">申请Lets证书</button>\
</div>\
</div>\
<ul class="help-info-text c7 pull-left">\
@@ -399,28 +400,50 @@ function getPanelSSL(){
closeBtn: 1,
shift: 5,
shadeClose: false,
content:certBody
content:certBody,
success:function(layero, layer_id){
//保存SSL
$('.save-panel-ssl').click(function(){
var data = {
privateKey:$("#key").val(),
certPem:$("#csr").val()
}
var loadT = layer.msg('正在安装并设置SSL组件,这需要几分钟时间...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/save_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
//申请Lets证书
$('.apply-lets-ssl').click(function(){
showSpeedWindow('正在申请...', 'site.get_let_logs', function(layers,index){
$.post('/config/apply_panel_let_ssl',{},function(rdata){
layer.close(loadT);
if(rdata.status){
layer.close(index);
var tdata = rdata['data'];
$('.ssl_issue').text(tdata['info']['issuer']);
$('.ssl_endtime').text("剩余"+tdata['info']['endtime']+"天到期");
$('.ssl_subject').text(tdata['info']['subject']);
$('textarea[name="key"]').val(tdata['info']['privateKey']);
$('textarea[name="csr"]').val(tdata['info']['certPem']);
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
});
}
});
},'json');
}
function savePanelSSL(){
var data = {
privateKey:$("#key").val(),
certPem:$("#csr").val()
}
var loadT = layer.msg('正在安装并设置SSL组件,这需要几分钟时间...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/save_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
}
function removeTempAccess(id){
$.post('/config/remove_temp_login', {id:id}, function(rdata){
showMsg(rdata.msg, function(){
+6 -6
View File
@@ -300,13 +300,12 @@ function openFilename(obj){
if (inArray(ext,['svg'])){
$.post("/files/get_body", "path=" + encodeURIComponent(path), function(rdata) {
if (rdata.data.status){
layer.open({
type:1,
closeBtn: 1,
title:false,
area: '600px',
title:"SVG预览",
area: '400px',
shadeClose: true,
content: '<div class="showpicdiv">'+rdata.data.data+'</div>'
});
@@ -1365,11 +1364,12 @@ function getImage(fileName){
var imgUrl = '/files/download?filename='+fileName;
layer.open({
type:1,
offset: '150px',
closeBtn: 1,
title:false,
area: '500px',
title:"图片预览",
area: '400px',
shadeClose: true,
content: '<div class="showpicdiv"><img src="'+imgUrl+'"></div>'
content: '<div class="showpicdiv"><img style="max-width:400px;" src="'+imgUrl+'"></div>'
});
}
+4
View File
@@ -16,6 +16,10 @@ function toSize(a) {
}
}
function toTrim(x) {
return x.replace(/^\s+|\s+$/gm,'');
}
function inArray(f, arr){
for (var i = 0; i < arr.length; i++) {
if (f == arr[i]) {
+1 -1
View File
@@ -2379,7 +2379,7 @@ function configFile(webSite){
function saveConfigFile(webSite,encoding,path){
var data = 'encoding='+encoding+'&data='+encodeURIComponent($("#configBody").val())+'&path='+path;
var loadT = layer.msg('保存中...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/files/save_body',data,function(rdata){
$.post('/site/save_host_conf',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.msg(rdata.msg,{icon:1});
+5 -5
View File
@@ -2903,23 +2903,23 @@ html .menu .menu_exit:hover {
}
.table>tbody>tr>td {
vertical-align: middle
vertical-align: middle;
}
.showpicdiv {
max-height: 500px;
max-height: 400px;
overflow: hidden;
width: 500px
width: 400px;
}
#BarTools {
font-size: 16px;
float: left;
margin-right: 20px
margin-right: 20px;
}
#BarTools>button {
top: 0
top: 0;
}
.comlist {
+3 -3
View File
@@ -28,16 +28,16 @@ elif grep -Eq "openSUSE" /etc/*-release; then
zypper install cron wget curl zip unzip
elif grep -Eq "FreeBSD" /etc/*-release; then
OSNAME='freebsd'
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/redhat-release; then
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Fedora" /etc/issue || grep -Eq "Fedora" /etc/*-release; then
OSNAME='fedora'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Rocky" /etc/issue || grep -Eq "Rocky" /etc/redhat-release; then
elif grep -Eqi "Rocky" /etc/issue || grep -Eq "Rocky" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "AlmaLinux" /etc/issue || grep -Eq "AlmaLinux" /etc/redhat-release; then
elif grep -Eqi "AlmaLinux" /etc/issue || grep -Eq "AlmaLinux" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Amazon Linux" /etc/issue || grep -Eq "Amazon Linux" /etc/*-release; then
+27 -14
View File
@@ -1,7 +1,12 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
LANG=C.UTF-8
export LANG=en_US.UTF-8
if [ ! -f /usr/bin/applydeltarpm ];then
yum -y provides '*/applydeltarpm'
yum -y install deltarpm
fi
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
@@ -28,27 +33,35 @@ if [ ! -d /root/.acme.sh ];then
curl https://get.acme.sh | sh
fi
echo "iptables wrap start"
if [ -f /usr/sbin/iptables ];then
$PKGMGR install -y iptables-services
# iptables -nL --line-number
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 888 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 7200 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 30000:40000 -j ACCEPT
service iptables save
iptables_status=`service iptables status | grep 'not running'`
if [ "${iptables_status}" == '' ];then
echo "iptables start"
iptables_status=`systemctl status iptables | grep 'inactive'`
if [ "${iptables_status}" != '' ];then
service iptables restart
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 888 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 7200 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 30000:40000 -j ACCEPT
service iptables save
fi
#安装时不开启
service iptables stop
# 安装时不开启
# stop之后清空了所有规则,所以安装是不能stop.
# 要在代码修复这个问题,开启时,重新执行一下放行端口。
#service iptables stop
echo "iptables end"
fi
echo "iptables wrap start"
if [ ! -f /usr/sbin/iptables ];then
$PKGMGR install firewalld -y
+1 -1
View File
@@ -6,7 +6,7 @@ is64bit=`getconf LONG_BIT`
echo -e "您正在安装的是\033[31mmdserver-web测试版\033[0m,非开发测试用途请使用正式版 install.sh !"
echo -e "You are installing\033[31mmdserver-web dev version\033[0m, normally use install.sh for production.\n"
sleep 2
sleep 1
{
+7 -1
View File
@@ -64,7 +64,13 @@ fi
cd /tmp && unzip /tmp/master.zip
/usr/bin/cp -rf /tmp/mdserver-web-master/* /www/server/mdserver-web
CP_CMD=/usr/bin/cp
if [ -f /bin/cp ];then
CP_CMD=/bin/cp
fi
$CP_CMD -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
rm -rf /tmp/master.zip
rm -rf /tmp/mdserver-web-master
+1 -1
View File
@@ -4,7 +4,7 @@ export PATH
export LANG=en_US.UTF-8
export DEBIAN_FRONTEND=noninteractive
localedef -v -c -i en_US -f UTF-8 en_US.UTF-8
# localedef -v -c -i en_US -f UTF-8 en_US.UTF-8
if grep -Eq "Ubuntu" /etc/*-release; then
sudo ln -sf /bin/bash /bin/sh
+8 -1
View File
@@ -63,7 +63,14 @@ fi
# wget -O /tmp/dev.zip https://github.com/midoks/mdserver-web/archive/refs/heads/dev.zip
cd /tmp && unzip /tmp/dev.zip
cp -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
CP_CMD=/usr/bin/cp
if [ -f /bin/cp ];then
CP_CMD=/bin/cp
fi
$CP_CMD -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
rm -rf /tmp/dev.zip
rm -rf /tmp/mdserver-web-dev
+32 -13
View File
@@ -17,6 +17,7 @@ import sys
import os
import json
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
@@ -46,18 +47,20 @@ def mwcli(mw_input=0):
raw_tip = "======================================================"
if not mw_input:
print("===============mdserver-web cli tools=================")
print("(1) 重启面板服务")
print("(2) 停止面板服务")
print("(3) 启动面板服务")
print("(4) 重载面板服务")
print("(5) 修改面板端口")
print("(10) 查看面板默认信息")
print("(11) 修改面板密码")
print("(12) 修改面板用户名")
print("(13) 显示面板错误日志")
print("(20) 关闭BasicAuth认证")
print("(21) 解除域名绑定")
print("(0) 取消")
print("(1) 重启面板服务")
print("(2) 停止面板服务")
print("(3) 启动面板服务")
print("(4) 重载面板服务")
print("(5) 修改面板端口")
print("(10) 查看面板默认信息")
print("(11) 修改面板密码")
print("(12) 修改面板用户名")
print("(13) 显示面板错误日志")
print("(20) 关闭BasicAuth认证")
print("(21) 解除域名绑定")
print("(100) 开启PHP52显示")
print("(101) 关闭PHP52显示")
print("(0) 取消")
print(raw_tip)
try:
mw_input = input("请输入命令编号:")
@@ -66,7 +69,7 @@ def mwcli(mw_input=0):
except:
mw_input = 0
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21]
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21, 100, 101]
if not mw_input in nums:
print(raw_tip)
print("已取消!")
@@ -116,6 +119,22 @@ def mwcli(mw_input=0):
os.remove(bind_domain)
os.system(INIT_CMD + " unbind_domain")
print("|-解除域名绑定成功")
elif mw_input == 100:
php_conf = 'plugins/php/info.json'
if os.path.exists(php_conf):
cont = mw.readFile(php_conf)
cont = re.sub("\"53\"", "\"52\",\"53\"", cont)
cont = re.sub("\"5.3.29\"", "\"5.2.17\",\"5.3.29\"", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52显示成功!")
elif mw_input == 101:
php_conf = 'plugins/php/info.json'
if os.path.exists(php_conf):
cont = mw.readFile(php_conf)
cont = re.sub("\"52\",", "", cont)
cont = re.sub("\"5.2.17\",", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52隐藏成功!")
def set_panel_pwd(password, ncli=False):