diff --git a/README.md b/README.md
index 170f2e8cb..03f140dbc 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@

[](https://github.com/midoks/mdserver-web/wiki)
+[](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
* SSH终端工具
* 面板收藏功能
@@ -59,6 +60,19 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
* mysql主从配置。
* swap插件[虚拟内存]。
+### jsdelivr [ 发布新版本生效 ]
+
+- 初始安装
+
+```
+curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
+```
+
+- 更新
+
+```
+curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
+```
### GW使用
@@ -90,7 +104,7 @@ curl -fsSL https://gitee.com/midoks/mdserver-web/raw/master/scripts/update_cn.s
-### 通用安装
+### 通用软件安装
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
diff --git a/class/core/config_api.py b/class/core/config_api.py
index 5c5b49dd5..429b3346d 100755
--- a/class/core/config_api.py
+++ b/class/core/config_api.py
@@ -15,9 +15,8 @@ from flask import request
class config_api:
- # 进行中.
- # 兼容主流Linux系统
- __version = '0.8.6.13'
+ # mariadb 优化
+ __version = '0.8.6.16'
def __init__(self):
pass
diff --git a/class/core/mw.py b/class/core/mw.py
index 6ca763223..70141afea 100755
--- a/class/core/mw.py
+++ b/class/core/mw.py
@@ -98,7 +98,12 @@ def systemdCfgDir():
return cfg_dir
# debian,centos
- return "/usr/lib/systemd/system"
+ cfg_dir = '/usr/lib/systemd/system'
+ if os.path.exists(cfg_dir):
+ return cfg_dir
+
+ # local test
+ return "/tmp"
def getOs():
@@ -261,6 +266,17 @@ def getRandomString(length):
return str
+def getUniqueId():
+ """
+ 根据时间生成唯一ID
+ :return:
+ """
+ current_time = datetime.datetime.now()
+ str_time = current_time.strftime('%Y%m%d%H%M%S%f')[:-3]
+ unique_id = "{0}".format(str_time)
+ return unique_id
+
+
def getJson(data):
import json
return json.dumps(data)
diff --git a/class/core/site_api.py b/class/core/site_api.py
index 0593284d6..ad597ada0 100755
--- a/class/core/site_api.py
+++ b/class/core/site_api.py
@@ -727,14 +727,14 @@ class site_api:
file = self.getHostConf(siteName)
conf = mw.readFile(file)
if conf:
- # if conf.find('ssl_certificate') == -1:
- # return mw.returnJson(False, '当前未开启SSL')
+ if conf.find('ssl_certificate') == -1:
+ return mw.returnJson(False, '当前未开启SSL')
to = """#error_page 404/404.html;
- # HTTP_TO_HTTPS_START
+ #HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
- # HTTP_TO_HTTPS_END"""
+ #HTTP_TO_HTTPS_END"""
conf = conf.replace('#error_page 404/404.html;', to)
mw.writeFile(file, conf)
@@ -2141,20 +2141,21 @@ location ^~ {from} {
content = content.replace('{$LOGPATH}', logsPath)
mw.writeFile(vhost_file, content)
- rewrite_content = '''
-location /{
- if ($PHP_ENV != "1"){
- break;
- }
-
- if (!-e $request_filename) {
- rewrite ^(.*)$ /index.php/$1 last;
- break;
- }
-}
-'''
+# 和反代配置冲突 && 默认伪静态为空
+# rewrite_content = '''
+# location /{
+# if ($PHP_ENV != "1"){
+# break;
+# }
+
+# if (!-e $request_filename) {
+# rewrite ^(.*)$ /index.php/$1 last;
+# break;
+# }
+# }
+# '''
rewrite_file = self.rewritePath + '/' + self.siteName + '.conf'
- mw.writeFile(rewrite_file, rewrite_content)
+ mw.writeFile(rewrite_file, '')
def add(self, webname, port, ps, path, version):
siteMenu = json.loads(webname)
diff --git a/class/plugin/orm.py b/class/plugin/orm.py
index 64ffd1790..aac2b9e36 100755
--- a/class/plugin/orm.py
+++ b/class/plugin/orm.py
@@ -24,13 +24,26 @@ class ORM:
'''连接数据库'''
try:
- try:
- self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
- port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, cursorclass=pymysql.cursors.DictCursor)
- except Exception as e:
- self.__DB_HOST = '127.0.0.1'
- self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
- port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, cursorclass=pymysql.cursors.DictCursor)
+ if os.path.exists(self.__DB_SOCKET):
+ try:
+ self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
+ unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
+ except Exception as e:
+ self.__DB_HOST = '127.0.0.1'
+ self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
+ unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
+ else:
+ try:
+ self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
+ cursorclass=pymysql.cursors.DictCursor)
+ except Exception as e:
+ self.__DB_HOST = '127.0.0.1'
+ self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
+ cursorclass=pymysql.cursors.DictCursor)
self.__DB_CUR = self.__DB_CONN.cursor()
return True
diff --git a/plugins/mariadb/conf/classic.cnf b/plugins/mariadb/conf/classic.cnf
new file mode 100644
index 000000000..e69de29bb
diff --git a/plugins/mariadb/conf/gtid.cnf b/plugins/mariadb/conf/gtid.cnf
new file mode 100644
index 000000000..5076776a6
--- /dev/null
+++ b/plugins/mariadb/conf/gtid.cnf
@@ -0,0 +1,4 @@
+[mysqld]
+# SHOW GLOBAL VARIABLES LIKE '%gtid%'
+gtid_mode=ON
+enforce_gtid_consistency=ON
\ No newline at end of file
diff --git a/plugins/mariadb/conf/mariadb.sql b/plugins/mariadb/conf/mariadb.sql
index 38b822738..f6df3e957 100755
--- a/plugins/mariadb/conf/mariadb.sql
+++ b/plugins/mariadb/conf/mariadb.sql
@@ -12,9 +12,11 @@ CREATE TABLE IF NOT EXISTS `databases` (
`username` TEXT,
`password` TEXT,
`accept` TEXT,
+ `rw` TEXT DEFAULT 'rw',
`ps` TEXT,
`addtime` TEXT
);
+-- ALTER TABLE `databases` ADD COLUMN `rw` TEXT DEFAULT 'rw';
CREATE TABLE IF NOT EXISTS `master_replication_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -25,4 +27,17 @@ CREATE TABLE IF NOT EXISTS `master_replication_user` (
`addtime` TEXT
);
+-- 从库配置主库的[ssh private key]
+-- drop table `slave_id_rsa`;
+CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `ip` TEXT,
+ `port` TEXT,
+ `user` TEXT,
+ `db_user` TEXT,
+ `id_rsa` TEXT,
+ `ps` TEXT,
+ `addtime` TEXT
+);
+
diff --git a/plugins/mariadb/conf/my.cnf b/plugins/mariadb/conf/my.cnf
index 4fd989170..8851e5b21 100644
--- a/plugins/mariadb/conf/my.cnf
+++ b/plugins/mariadb/conf/my.cnf
@@ -5,6 +5,9 @@ port = 33106
socket = {$SERVER_APP_PATH}/mysql.sock
[mysqld]
+
+!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
+
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 33106
@@ -12,7 +15,10 @@ socket = {$SERVER_APP_PATH}/mysql.sock
basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
-default_storage_engine = MyISAM
+server-id = {$SERVER_ID}
+
+default_storage_engine = InnoDB
+
key_buffer_size = 8M
max_allowed_packet = 100M
table_open_cache = 32
@@ -30,8 +36,8 @@ max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
+skip-name-resolve = on
#skip-networking
-#skip-name-resolve
#skip-external-locking
#loose-skip-innodb
#skip-grant-tables
@@ -39,7 +45,6 @@ open_files_limit = 65535
log-bin=mysql-bin
binlog_format=mixed
-server-id = 1
expire_logs_days = 10
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
@@ -64,7 +69,7 @@ replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
-default_storage_engine = InnoDB
+
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
@@ -75,7 +80,7 @@ innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
-innodb_write_io_threads = 1
+innodb_write_io_threads = 2
innodb_file_per_table=1
diff --git a/plugins/mariadb/index.html b/plugins/mariadb/index.html
index 80a73bb58..24065d6e0 100755
--- a/plugins/mariadb/index.html
+++ b/plugins/mariadb/index.html
@@ -13,6 +13,7 @@
diff --git a/plugins/mariadb/index.py b/plugins/mariadb/index.py
index e41d47cc4..9ba058bd2 100755
--- a/plugins/mariadb/index.py
+++ b/plugins/mariadb/index.py
@@ -120,6 +120,13 @@ def contentReplace(content):
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$SERVER_APP_PATH}', service_path + '/mariadb')
+ server_id = int(time.time())
+ content = content.replace('{$SERVER_ID}', str(server_id))
+
+ if mw.isAppleSystem():
+ user = mw.execShell(
+ "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
+ content = content.replace('user = mysql', 'user = ' + user)
return content
@@ -158,6 +165,25 @@ def pMysqlDb():
return db
+def makeInitRsaKey(version=''):
+ datadir = getServerDir() + "/data"
+
+ mysql_pem = datadir + "/mysql.pem"
+ if not os.path.exists(mysql_pem):
+ rdata = mw.execShell(
+ 'cd ' + datadir + ' && openssl genrsa -out mysql.pem 1024')
+ # print(data)
+ rdata = mw.execShell(
+ 'cd ' + datadir + ' && openssl rsa -in mysql.pem -pubout -out mysql.pub')
+ # print(rdata)
+
+ if not mw.isAppleSystem():
+ mw.execShell('cd ' + datadir + ' && chmod 400 mysql.pem')
+ mw.execShell('cd ' + datadir + ' && chmod 444 mysql.pub')
+ mw.execShell('cd ' + datadir + ' && chown mysql:mysql mysql.pem')
+ mw.execShell('cd ' + datadir + ' && chown mysql:mysql mysql.pub')
+
+
def initDreplace(version=''):
initd_tpl = getInitdTpl(version)
@@ -306,28 +332,36 @@ def initMysqlData():
cmd = 'cd ' + serverdir + ' && ./scripts/mariadb-install-db ' + \
' --defaults-file=' + myconf
data = mw.execShell(cmd)
- # print(data)
+ # print(data[0])
+ # print(data[1])
return False
return True
-def initMysqlPwd():
+def initMariaDbPwd():
time.sleep(5)
serverdir = getServerDir()
pwd = mw.getRandomString(16)
- cmd_pass = serverdir + '/bin/mysql -S ' + serverdir + '/mysql.sock -uroot -e'
+ db_option = "-S " + serverdir + "/mysql.sock"
+ cmd_pass = serverdir + '/bin/mysql ' + db_option + ' -uroot -e'
cmd_pass = cmd_pass + \
- "\"grant all privileges on *.* to 'root'@'localhost' identified by '" + pwd + "';"
+ "\"flush privileges;use mysql;grant all privileges on *.* to 'root'@'localhost' identified by '" + pwd + "';"
cmd_pass = cmd_pass + "flush privileges;\""
+ # print(cmd_pass)
data = mw.execShell(cmd_pass)
# print(data)
if data[1].find("ERROR") != -1:
print("init mariadb password fail:" + data[1])
exit(1)
+ # 删除测试数据库
+ drop_test_db = serverdir + '/bin/mysql ' + db_option + ' -uroot -p' + \
+ pwd + ' -e "drop database test";'
+ mw.execShell(drop_test_db)
+
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
return True
@@ -335,20 +369,46 @@ def initMysqlPwd():
def myOp(version, method):
# import commands
init_file = initDreplace()
+ cmd = init_file + ' ' + method
try:
isInited = initMysqlData()
if not isInited:
- mw.execShell('systemctl start mariadb')
- initMysqlPwd()
- mw.execShell('systemctl stop mariadb')
+ if mw.isAppleSystem():
+ setSkipGrantTables(True)
+ cmd_init_start = init_file + ' start'
+ subprocess.Popen(cmd_init_start, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+
+ time.sleep(6)
+ else:
+ mw.execShell('systemctl start mariadb')
+
+ initMariaDbPwd()
+
+ if mw.isAppleSystem():
+ setSkipGrantTables(False)
+ cmd_init_stop = init_file + ' stop'
+ subprocess.Popen(cmd_init_stop, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+ time.sleep(3)
+ else:
+ mw.execShell('systemctl stop mariadb')
+
+ if mw.isAppleSystem():
+ print
+ sub = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+ sub.wait(5)
+ else:
+ mw.execShell('systemctl ' + method + ' mariadb')
- mw.execShell('systemctl ' + method + ' mariadb')
return 'ok'
except Exception as e:
return str(e)
def appCMD(version, action):
+ makeInitRsaKey(version)
return myOp(version, action)
@@ -493,8 +553,8 @@ def runInfo():
result['Run'] = int(time.time()) - int(result['Uptime'])
tmp = db.query('show master status')
try:
- result['File'] = tmp[0][0]
- result['Position'] = tmp[0][1]
+ result['File'] = tmp[0]["File"]
+ result['Position'] = tmp[0]["Position"]
except:
result['File'] = 'OFF'
result['Position'] = 'OFF'
@@ -570,16 +630,6 @@ def isSqlError(mysqlMsg):
return None
-def mapToList(map_obj):
- # map to list
- try:
- if type(map_obj) != list and type(map_obj) != str:
- map_obj = list(map_obj)
- return map_obj
- except:
- return []
-
-
def __createUser(dbname, username, password, address):
pdb = pMysqlDb()
@@ -618,9 +668,8 @@ def setDbBackup():
if not data[0]:
return data[1]
- scDir = mw.getRunDir() + '/scripts/backup.py'
-
- cmd = 'python ' + scDir + ' database ' + args['name'] + ' 3'
+ scDir = getPluginDir() + '/scripts/backup.py'
+ cmd = 'python3 ' + scDir + ' database ' + args['name'] + ' 3'
os.system(cmd)
return mw.returnJson(True, 'ok')
@@ -711,7 +760,7 @@ def getDbList():
condition = ''
if not search == '':
condition = "name like '%" + search + "%'"
- field = 'id,pid,name,username,password,accept,ps,addtime'
+ field = 'id,pid,name,username,password,accept,rw,ps,addtime'
clist = conn.where(condition, ()).field(
field).limit(limit).order('id desc').select()
@@ -836,7 +885,7 @@ def syncToDatabases():
return mw.returnJson(True, msg)
-def setRootPwd():
+def setRootPwd(version=''):
args = getArgs()
data = checkArgs(args, ['password'])
if not data[0]:
@@ -850,17 +899,8 @@ def setRootPwd():
if isError != None:
return isError
- m_version = mw.readFile(getServerDir() + '/version.pl')
- if m_version.find('5.7') == 0 or m_version.find('8.0') == 0:
- pdb.execute(
- "UPDATE mysql.user SET authentication_string='' WHERE user='root'")
- pdb.execute(
- "ALTER USER 'root'@'localhost' IDENTIFIED BY '%s'" % password)
- pdb.execute(
- "ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '%s'" % password)
- else:
- result = pdb.execute(
- "update mysql.user set Password=password('" + password + "') where User='root'")
+ result = pdb.execute(
+ "update mysql.user set Password=password('" + password + "') where User='root'")
pdb.execute("flush privileges")
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '数据库root密码修改成功!')
@@ -868,7 +908,7 @@ def setRootPwd():
return mw.returnJson(False, '修改错误:' + str(ex))
-def setUserPwd():
+def setUserPwd(version=''):
args = getArgs()
data = checkArgs(args, ['password', 'name'])
if not data[0]:
@@ -882,27 +922,14 @@ def setUserPwd():
psdb = pSqliteDb('databases')
name = psdb.where('id=?', (uid,)).getField('name')
- m_version = mw.readFile(getServerDir() + '/version.pl')
- if m_version.find('5.7') == 0 or m_version.find('8.0') == 0:
- accept = pdb.query(
- "select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
- pdb.execute(
- "update mysql.user set authentication_string='' where User='" + username + "'")
- result = pdb.execute(
- "ALTER USER `%s`@`localhost` IDENTIFIED BY '%s'" % (username, newpassword))
- for my_host in accept:
- pdb.execute("ALTER USER `%s`@`%s` IDENTIFIED BY '%s'" % (
- username, my_host["Host"], newpassword))
- else:
- result = pdb.execute("update mysql.user set Password=password('" +
- newpassword + "') where User='" + username + "'")
+ result = pdb.execute("update mysql.user set Password=password('" +
+ newpassword + "') where User='" + username + "'")
pdb.execute("flush privileges")
- psdb.where("id=?", (id,)).setField('password', newpassword)
+ psdb.where("id=?", (uid,)).setField('password', newpassword)
return mw.returnJson(True, mw.getInfo('修改数据库[{1}]密码成功!', (name,)))
except Exception as ex:
- print(str(ex))
- return mw.returnJson(False, mw.getInfo('修改数据库[{1}]密码失败!', (name,)))
+ return mw.returnJson(False, mw.getInfo('修改数据库[{1}]密码失败[{2}]!', (name, str(ex),)))
def setDbPs():
@@ -955,8 +982,8 @@ def addDb():
wheres = {
'utf8': 'utf8_general_ci',
- 'utf8mb4': 'utf8mb4_general_ci',
- 'gbk': 'gbk_chinese_ci',
+ 'utf8mb4': 'utf8mb4_general_ci',
+ 'gbk': 'gbk_chinese_ci',
'big5': 'big5_chinese_ci'
}
codeStr = wheres[codeing]
@@ -1029,10 +1056,6 @@ def getDbAccess():
users = pdb.query("select Host from mysql.user where User='" +
username + "' AND Host!='localhost'")
- # isError = isSqlError(users)
- # if isError != None:
- # return isError
-
if len(users) < 1:
return mw.returnJson(True, "127.0.0.1")
accs = []
@@ -1042,19 +1065,6 @@ def getDbAccess():
return mw.returnJson(True, userStr)
-def toSize(size):
- d = ('b', 'KB', 'MB', 'GB', 'TB')
- s = d[0]
- for b in d:
- if size < 1024:
- return str(size) + ' ' + b
- size = size / 1024
- s = b
- _size = round(size, 2)
- # print(size, _size)
- return str(size) + ' ' + b
-
-
def setDbAccess():
args = getArgs()
data = checkArgs(args, ['username', 'access'])
@@ -1081,10 +1091,51 @@ def setDbAccess():
__createUser(dbname, name, password, access)
- psdb.where('username=?', (name,)).save('accept', (access,))
+ psdb.where('username=?', (name,)).save('accept,rw', (access, 'rw',))
return mw.returnJson(True, '设置成功!')
+def setDbRw(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['username', 'id', 'rw'])
+ if not data[0]:
+ return data[1]
+
+ username = args['username']
+ uid = args['id']
+ rw = args['rw']
+
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+ dbname = psdb.where("id=?", (uid,)).getField('name')
+ users = pdb.query(
+ "select Host from mysql.user where User='" + username + "'")
+
+ # show grants for demo@"127.0.0.1";
+ for x in users:
+ # REVOKE ALL PRIVILEGES ON `imail`.* FROM 'imail'@'127.0.0.1';
+
+ sql = "REVOKE ALL PRIVILEGES ON `" + dbname + \
+ "`.* FROM '" + username + "'@'" + x["Host"] + "';"
+ r = pdb.query(sql)
+ # print(sql, r)
+
+ if rw == 'rw':
+ sql = "GRANT SELECT, INSERT, UPDATE, DELETE ON " + dbname + ".* TO " + \
+ username + "@'" + x["Host"] + "'"
+ elif rw == 'r':
+ sql = "GRANT SELECT ON " + dbname + ".* TO " + \
+ username + "@'" + x["Host"] + "'"
+ else:
+ sql = "GRANT all privileges ON " + dbname + ".* TO " + \
+ username + "@'" + x["Host"] + "'"
+ pdb.execute(sql)
+ pdb.execute("flush privileges")
+ r = psdb.where("id=?", (uid,)).setField('rw', rw)
+ # print(r)
+ return mw.returnJson(True, '切换成功!')
+
+
def getDbInfo():
args = getArgs()
data = checkArgs(args, ['name'])
@@ -1097,9 +1148,12 @@ def getDbInfo():
tables = pdb.query('show tables from `%s`' % db_name)
ret = {}
- data_sum = pdb.query(
- "select sum(DATA_LENGTH)+sum(INDEX_LENGTH) as sum_size from information_schema.tables where table_schema='%s'" % db_name)
- data = data_sum[0]['sum_size']
+ sql = "select sum(DATA_LENGTH)+sum(INDEX_LENGTH) as sum_size from information_schema.tables where table_schema='%s'" % db_name
+ data_sum = pdb.query(sql)
+
+ data = 0
+ if data_sum[0]['sum_size'] != None:
+ data = data_sum[0]['sum_size']
ret['data_size'] = mw.toSize(data)
ret['database'] = db_name
@@ -1107,14 +1161,22 @@ def getDbInfo():
ret3 = []
table_key = "Tables_in_" + db_name
for i in tables:
- table = pdb.query(
- "show table status from `%s` where name = '%s'" % (db_name, i[table_key]))
+ tb_sql = "show table status from `%s` where name = '%s'" % (db_name, i[
+ table_key])
+ table = pdb.query(tb_sql)
tmp = {}
tmp['type'] = table[0]["Engine"]
tmp['rows_count'] = table[0]["Rows"]
tmp['collation'] = table[0]["Collation"]
- data_size = table[0]["Avg_row_length"] + table[0]["Data_length"]
+
+ data_size = 0
+ if table[0]['Avg_row_length'] != None:
+ data_size = table[0]['Avg_row_length']
+
+ if table[0]['Data_length'] != None:
+ data_size = table[0]['Data_length']
+
tmp['data_byte'] = data_size
tmp['data_size'] = mw.toSize(data_size)
tmp['table_name'] = table[0]["Name"]
@@ -1218,6 +1280,74 @@ def getTotalStatistics():
return mw.returnJson(False, 'fail', data)
+def recognizeDbMode():
+ conf = getConf()
+ con = mw.readFile(conf)
+ rep = r"!include %s/(.*)?\.cnf" % (getServerDir() + "/etc/mode",)
+ mode = 'none'
+ try:
+ data = re.findall(rep, con, re.M)
+ mode = data[0]
+ except Exception as e:
+ pass
+ return mode
+
+
+def getDbrunMode(version=''):
+ mode = recognizeDbMode()
+ return mw.returnJson(True, "ok", {'mode': mode})
+
+
+def setDbrunMode(version=''):
+ if version == '5.5':
+ return mw.returnJson(False, "不支持切换")
+
+ args = getArgs()
+ data = checkArgs(args, ['mode', 'reload'])
+ if not data[0]:
+ return data[1]
+
+ mode = args['mode']
+ dbreload = args['reload']
+
+ if not mode in ['classic', 'gtid']:
+ return mw.returnJson(False, "mode的值无效:" + mode)
+
+ origin_mode = recognizeDbMode()
+ path = getConf()
+ con = mw.readFile(path)
+ rep = r"!include %s/%s\.cnf" % (getServerDir() + "/etc/mode", origin_mode)
+ rep_after = "!include %s/%s.cnf" % (getServerDir() + "/etc/mode", mode)
+ con = re.sub(rep, rep_after, con)
+ mw.writeFile(path, con)
+
+ if version == '5.6':
+ dbreload = 'yes'
+ else:
+ db = pMysqlDb()
+ # The value of @@GLOBAL.GTID_MODE can only be changed one step at a
+ # time: OFF <-> OFF_PERMISSIVE <-> ON_PERMISSIVE <-> ON. Also note that
+ # this value must be stepped up or down simultaneously on all servers.
+ # See the Manual for instructions.
+ if mode == 'classic':
+ db.query('set global enforce_gtid_consistency=off')
+ db.query('set global gtid_mode=on')
+ db.query('set global gtid_mode=on_permissive')
+ db.query('set global gtid_mode=off_permissive')
+ db.query('set global gtid_mode=off')
+ elif mode == 'gtid':
+ db.query('set global enforce_gtid_consistency=on')
+ db.query('set global gtid_mode=off')
+ db.query('set global gtid_mode=off_permissive')
+ db.query('set global gtid_mode=on_permissive')
+ db.query('set global gtid_mode=on')
+
+ if dbreload == "yes":
+ restart(version)
+
+ return mw.returnJson(True, "切换成功!")
+
+
def findBinlogDoDb():
conf = getConf()
con = mw.readFile(conf)
@@ -1234,6 +1364,33 @@ def findBinlogSlaveDoDb():
return dodb
+def setDbMasterAccess():
+ args = getArgs()
+ data = checkArgs(args, ['username', 'access'])
+ if not data[0]:
+ return data[1]
+ username = args['username']
+ access = args['access']
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('master_replication_user')
+ password = psdb.where("username=?", (username,)).getField('password')
+ users = pdb.query("select Host from mysql.user where User='" +
+ username + "' AND Host!='localhost'")
+ for us in users:
+ pdb.execute("drop user '" + username + "'@'" + us["Host"] + "'")
+
+ dbname = '*'
+ for a in access.split(','):
+ pdb.execute(
+ "CREATE USER `%s`@`%s` IDENTIFIED BY '%s'" % (username, a, password))
+ pdb.execute(
+ "grant all privileges on %s.* to `%s`@`%s`" % (dbname, username, a))
+
+ pdb.execute("flush privileges")
+ psdb.where('username=?', (username,)).save('accept', (access,))
+ return mw.returnJson(True, '设置成功!')
+
+
def getMasterDbList(version=''):
args = getArgs()
page = 1
@@ -1353,13 +1510,15 @@ def getMasterStatus(version=''):
return mw.returnJson(False, 'MySQL未启动,或正在启动中...!', [])
conf = getConf()
- con = mw.readFile(conf)
+ content = mw.readFile(conf)
master_status = False
- if con.find('#log-bin') == -1 and con.find('log-bin') > 1:
+ if content.find('#log-bin') == -1 and content.find('log-bin') > 1:
dodb = findBinlogDoDb()
if len(dodb) > 0:
master_status = True
+
data = {}
+ data['mode'] = recognizeDbMode()
data['status'] = master_status
db = pMysqlDb()
@@ -1437,10 +1596,6 @@ def getMasterRepSlaveList(version=''):
def addMasterRepSlaveUser(version=''):
- version_pl = getServerDir() + "/version.pl"
- if os.path.exists(version_pl):
- version = mw.readFile(version_pl).strip()
-
args = getArgs()
data = checkArgs(args, ['username', 'password'])
if not data[0]:
@@ -1475,25 +1630,13 @@ def addMasterRepSlaveUser(version=''):
if psdb.where("username=?", (username)).count() > 0:
return mw.returnJson(False, '用户已存在!')
- if version == "8.0":
- sql = "CREATE USER '" + username + \
- "' IDENTIFIED WITH mysql_native_password BY '" + password + "';"
- pdb.execute(sql)
- sql = "grant replication slave on *.* to '" + username + "'@'%';"
- result = pdb.execute(sql)
- isError = isSqlError(result)
- if isError != None:
- return isError
-
- sql = "FLUSH PRIVILEGES;"
- pdb.execute(sql)
- else:
- sql = "GRANT REPLICATION SLAVE ON *.* TO '" + username + \
- "'@'%' identified by '" + password + "';FLUSH PRIVILEGES;"
- result = pdb.execute(sql)
- isError = isSqlError(result)
- if isError != None:
- return isError
+ 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
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
psdb.add('username,password,accept,ps,addtime',
@@ -1503,10 +1646,6 @@ def addMasterRepSlaveUser(version=''):
def getMasterRepSlaveUserCmd(version):
- version_pl = getServerDir() + "/version.pl"
- if os.path.exists(version_pl):
- version = mw.readFile(version_pl).strip()
-
args = getArgs()
data = checkArgs(args, ['username', 'db'])
if not data[0]:
@@ -1514,40 +1653,44 @@ def getMasterRepSlaveUserCmd(version):
psdb = pSqliteDb('master_replication_user')
f = 'username,password'
- if args['username'] == '':
-
+ username = args['username']
+ if username == '':
count = psdb.count()
-
if count == 0:
return mw.returnJson(False, '请添加同步账户!')
clist = psdb.field(f).limit('1').order('id desc').select()
else:
- clist = psdb.field(f).where("username=?", (args['username'],)).limit(
+ clist = psdb.field(f).where("username=?", (username,)).limit(
'1').order('id desc').select()
ip = mw.getLocalIp()
port = getMyPort()
-
db = pMysqlDb()
+
mstatus = db.query('show master status')
if len(mstatus) == 0:
return mw.returnJson(False, '未开启!')
- sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
- clist[0]['username'] + "', MASTER_PASSWORD='" + \
- clist[0]['password'] + \
- "', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
- "',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + ""
+ mode = recognizeDbMode()
- if version == "8.0":
- sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
- clist[0]['username'] + "', SOURCE_PASSWORD='" + \
+ 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"
+ else:
+ sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
+ clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + \
- "', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
- "',SOURCE_LOG_POS=" + str(mstatus[0]["Position"]) + ""
+ "', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
+ "',MASTER_LOG_POS=" + str(mstatus[0]["Position"])
- return mw.returnJson(True, 'OK!', sql)
+ data = {}
+ data['cmd'] = sql
+ data["info"] = clist[0]
+ data['mode'] = mode
+
+ return mw.returnJson(True, 'ok!', data)
def delMasterRepSlaveUser(version=''):
@@ -1556,9 +1699,18 @@ def delMasterRepSlaveUser(version=''):
if not data[0]:
return data[1]
+ name = args['username']
+
pdb = pMysqlDb()
psdb = pSqliteDb('master_replication_user')
- pdb.execute("drop user '" + args['username'] + "'@'%'")
+ pdb.execute("drop user '" + name + "'@'%'")
+ pdb.execute("drop user '" + name + "'@'localhost'")
+
+ users = pdb.query("select Host from mysql.user where User='" +
+ name + "' AND Host!='localhost'")
+ for us in users:
+ pdb.execute("drop user '" + name + "'@'" + us["Host"] + "'")
+
psdb.where("username=?", (args['username'],)).delete()
return mw.returnJson(True, '删除成功!')
@@ -1595,7 +1747,7 @@ def getSlaveSSHList(version=''):
conn = pSqliteDb('slave_id_rsa')
limit = str((page - 1) * page_size) + ',' + str(page_size)
- field = 'id,ip,port,id_rsa,ps,addtime'
+ field = 'id,ip,port,db_user,id_rsa,ps,addtime'
clist = conn.field(field).limit(limit).order('id desc').select()
count = conn.count()
@@ -1620,7 +1772,7 @@ def getSlaveSSHByIp(version=''):
ip = args['ip']
conn = pSqliteDb('slave_id_rsa')
- data = conn.field('ip,port,id_rsa').where("ip=?", (ip,)).select()
+ data = conn.field('ip,port,db_user,id_rsa').where("ip=?", (ip,)).select()
return mw.returnJson(True, 'ok', data)
@@ -1636,22 +1788,24 @@ def addSlaveSSH(version=''):
if ip == "":
return mw.returnJson(True, 'ok')
- data = checkArgs(args, ['port', 'id_rsa'])
+ data = checkArgs(args, ['port', 'id_rsa', 'db_user'])
if not data[0]:
return data[1]
id_rsa = args['id_rsa']
port = args['port']
+ db_user = args['db_user']
user = 'root'
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
conn = pSqliteDb('slave_id_rsa')
data = conn.field('ip,id_rsa').where("ip=?", (ip,)).select()
if len(data) > 0:
- res = conn.where("ip=?", (ip,)).save('port,id_rsa', (port, id_rsa,))
+ res = conn.where("ip=?", (ip,)).save(
+ 'port,id_rsa,db_user', (port, id_rsa, db_user))
else:
- conn.add('ip,port,user,id_rsa,ps,addtime',
- (ip, port, user, id_rsa, '', addTime))
+ conn.add('ip,port,user,id_rsa,db_user,ps,addtime',
+ (ip, port, user, id_rsa, db_user, '', addTime))
return mw.returnJson(True, '设置成功!')
@@ -1686,6 +1840,8 @@ def getSlaveList(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
+
+ # print(dlist)
ret = []
for x in range(0, len(dlist)):
tmp = {}
@@ -1705,66 +1861,139 @@ def getSlaveList(version=''):
def getSlaveSyncCmd(version=''):
root = mw.getRunDir()
- cmd = 'cd ' + root + ' && python ' + root + \
+ cmd = 'cd ' + root + ' && python3 ' + root + \
'/plugins/mysql/index.py do_full_sync {"db":"all"}'
return mw.returnJson(True, 'ok', cmd)
+def initSlaveStatus(version=''):
+ db = pMysqlDb()
+ dlist = db.query('show slave status')
+ if len(dlist) > 0:
+ return mw.returnJson(False, '已经初始化好了zz...')
+
+ conn = pSqliteDb('slave_id_rsa')
+ data = conn.field('ip,port,id_rsa,db_user').find()
+
+ if len(data) < 1:
+ return mw.returnJson(False, '需要先配置【[主]SSH配置】!')
+
+ SSH_PRIVATE_KEY = "/tmp/t_ssh.txt"
+ ip = data['ip']
+ master_port = data['port']
+ mw.writeFile(SSH_PRIVATE_KEY, data['id_rsa'].replace('\\n', '\n'))
+
+ import paramiko
+ paramiko.util.log_to_file('paramiko.log')
+ ssh = paramiko.SSHClient()
+
+ try:
+
+ mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
+ key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ ssh.connect(hostname=ip, port=int(master_port),
+ username='root', pkey=key)
+
+ db_user = data['db_user']
+ cmd = 'cd /www/server/mdserver-web && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
+ stdin, stdout, stderr = ssh.exec_command(cmd)
+ result = stdout.read()
+ result = result.decode('utf-8')
+ cmd_data = json.loads(result)
+ time.sleep(1)
+ ssh.close()
+ if not cmd_data['status']:
+ return mw.returnJson(False, '[主]:' + cmd_data['msg'])
+
+ local_mode = recognizeDbMode()
+ if local_mode != cmd_data['data']['mode']:
+ return mw.returnJson(False, '主【{}】从【{}】,运行模式不一致!'.format(cmd_data['data']['mode'], local_mode))
+
+ u = cmd_data['data']['info']
+ ps = u['username'] + "|" + u['password']
+ conn.where('ip=?', (ip,)).setField('ps', ps)
+ db.query('stop slave')
+
+ # 保证同步IP一致
+ cmd = cmd_data['data']['cmd']
+ if cmd.find('SOURCE_HOST') > -1:
+ cmd = re.sub(r"SOURCE_HOST='(.*?)'",
+ "SOURCE_HOST='" + ip + "'", cmd, 1)
+
+ if cmd.find('MASTER_HOST') > -1:
+ cmd = re.sub(r"MASTER_HOST='(.*?)'",
+ "MASTER_HOST='" + ip + "'", cmd, 1)
+
+ # print(cmd)
+ db.query(cmd)
+ db.query("start slave")
+
+ except Exception as e:
+ return mw.returnJson(False, 'SSH认证配置连接失败!' + str(e))
+
+ os.system("rm -rf " + SSH_PRIVATE_KEY)
+ return mw.returnJson(True, '初始化成功!')
+
+
def setSlaveStatus(version=''):
+
db = pMysqlDb()
dlist = db.query('show slave status')
if len(dlist) == 0:
- return mw.returnJson(False, '需要手动添加主服务同步命令!')
+ return mw.returnJson(False, '需要手动添加主服务命令或者执行[初始化]!')
+ # print(dlist)
if len(dlist) > 0 and (dlist[0]["Slave_IO_Running"] == 'Yes' or dlist[0]["Slave_SQL_Running"] == 'Yes'):
db.query('stop slave')
else:
- db.query('start slave')
+ ip = dlist[0]['Master_Host']
+ conn = pSqliteDb('slave_id_rsa')
+ data = conn.field('ip,ps').where("ip=?", (ip,)).find()
+ if len(data) == 0:
+ return mw.returnJson(False, '没有数据无法重启!')
+ db.query("start slave")
return mw.returnJson(True, '设置成功!')
def deleteSlave(version=''):
db = pMysqlDb()
- dlist = db.query('stop slave;reset slave all')
+ dlist = db.query('stop slave')
+ dlist = db.query('reset slave all')
return mw.returnJson(True, '删除成功!')
-def dumpMysqlData(version):
-
+def dumpMysqlData(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
- if args['db'] == 'all' or args['db'] == 'ALL':
+ mysql_dir = getServerDir()
+ myconf = mysql_dir + "/etc/my.cnf"
+
+ option = ''
+ mode = recognizeDbMode()
+ if mode == 'gtid':
+ option = ' --set-gtid-purged=off '
+
+ if args['db'].lower() == 'all':
dlist = findBinlogDoDb()
- cmd = getServerDir() + "/bin/mysqldump -uroot -p" + \
- pwd + " --databases " + ' '.join(dlist) + \
- " > /tmp/dump.sql"
+ cmd = mysql_dir + "/bin/mysqldump --defaults-file=" + myconf + " " + option + " -uroot -p" + \
+ pwd + " --databases " + \
+ ' '.join(dlist) + " | gzip > /tmp/dump.sql.gz"
else:
- cmd = getServerDir() + "/bin/mysqldump -uroot -p" + pwd + \
- " --databases " + args['db'] + " > /tmp/dump.sql"
+ cmd = mysql_dir + "/bin/mysqldump --defaults-file=" + myconf + " " + option + " -uroot -p" + \
+ pwd + " --databases " + args['db'] + " | gzip > /tmp/dump.sql.gz"
ret = mw.execShell(cmd)
-
if ret[0] == '':
return 'ok'
return 'fail'
-from threading import Thread
-from time import sleep
-
-
-def mw_async(f):
- def wrapper(*args, **kwargs):
- thr = Thread(target=f, args=args, kwargs=kwargs)
- thr.start()
- return wrapper
-
-
############### --- 重要 同步---- ###########
def writeDbSyncStatus(data):
@@ -1775,37 +2004,26 @@ def writeDbSyncStatus(data):
mw.writeFile(path, json.dumps(data))
-def doFullSync():
+def doFullSync(version=''):
args = getArgs()
data = checkArgs(args, ['db'])
if not data[0]:
return data[1]
- arg_db_select = args['db']
-
- status_data = {}
- status_data['progress'] = 5
-
db = pMysqlDb()
- dlist = db.query('show slave status')
- if len(dlist) == 0:
- status_data['code'] = -1
- status_data['msg'] = '没有启动...'
-
- ip = dlist[0]["Master_Host"]
- print("master ip:", ip)
-
id_rsa_conn = pSqliteDb('slave_id_rsa')
- data = id_rsa_conn.field('ip,port,id_rsa').where("ip=?", (ip,)).select()
+ data = id_rsa_conn.field('ip,port,db_user,id_rsa').find()
SSH_PRIVATE_KEY = "/tmp/mysql_sync_id_rsa.txt"
- id_rsa_key = data[0]['id_rsa']
- id_rsa_key = id_rsa_key.replace('\\n', '\n')
- master_port = int(data[0]['port'])
+ id_rsa = data['id_rsa'].replace('\\n', '\n')
+ mw.writeFile(SSH_PRIVATE_KEY, id_rsa)
- mw.writeFile(SSH_PRIVATE_KEY, id_rsa_key)
+ ip = data["ip"]
+ master_port = data['port']
+ db_user = data['db_user']
+ print("master ip:", ip)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
@@ -1819,15 +2037,15 @@ def doFullSync():
return 'fail'
try:
+ # ssh.load_system_host_keys()
mw.execShell("chmod 600 " + SSH_PRIVATE_KEY)
key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
- # ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print(ip, master_port)
# pkey=key
# key_filename=SSH_PRIVATE_KEY
- ssh.connect(hostname=ip, port=master_port,
+ ssh.connect(hostname=ip, port=int(master_port),
username='root', pkey=key)
except Exception as e:
print(str(e))
@@ -1836,53 +2054,69 @@ def doFullSync():
return 'fail'
writeDbSyncStatus({'code': 0, 'msg': '登录Master成功...', 'progress': 5})
-
- cmd = "cd /www/server/mdserver-web && python /www/server/mdserver-web/plugins/mysql/index.py dump_mysql_data {\"db\":'" + args[
- 'db'] + "'}"
+ dbname = args['db']
+ cmd = "cd /www/server/mdserver-web && python3 plugins/mariadb/index.py dump_mysql_data {\"db\":'" + dbname + "'}"
+ print(cmd)
stdin, stdout, stderr = ssh.exec_command(cmd)
result = stdout.read()
- result_err = stderr.read()
-
result = result.decode('utf-8')
- # print(result)
if result.strip() == 'ok':
writeDbSyncStatus({'code': 1, 'msg': '主服务器备份完成...', 'progress': 30})
else:
- writeDbSyncStatus({'code': 1, 'msg': '主服务器备份失败...', 'progress': 30})
+ writeDbSyncStatus(
+ {'code': 1, 'msg': '主服务器备份失败...:' + str(result), 'progress': 100})
return 'fail'
- r = mw.execShell('scp root@' + ip + ':/tmp/dump.sql /tmp')
- if r[0] == '':
+ print("同步文件", "start")
+ # cmd = 'scp -P' + str(master_port) + ' -i ' + SSH_PRIVATE_KEY + \
+ # ' root@' + ip + ':/tmp/dump.sql.gz /tmp'
+ t = ssh.get_transport()
+ sftp = paramiko.SFTPClient.from_transport(t)
+ copy_status = sftp.get("/tmp/dump.sql.gz", "/tmp/dump.sql.gz")
+ print("同步信息:", copy_status)
+ print("同步文件", "end")
+ if copy_status == None:
writeDbSyncStatus({'code': 2, 'msg': '数据同步本地完成...', 'progress': 40})
- cmd = 'cd /www/server/mdserver-web && python /www/server/mdserver-web/plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}'
+ cmd = 'cd /www/server/mdserver-web && python3 plugins/mariadb/index.py get_master_rep_slave_user_cmd {"username":"' + db_user + '","db":""}'
stdin, stdout, stderr = ssh.exec_command(cmd)
result = stdout.read()
- result_err = stderr.read()
+ result = result.decode('utf-8')
cmd_data = json.loads(result)
- # print(cmd_data)
db.query('stop slave')
writeDbSyncStatus({'code': 3, 'msg': '停止从库完成...', 'progress': 45})
- dlist = db.query(cmd_data['data'])
+ cmd = cmd_data['data']['cmd']
+ # 保证同步IP一致
+ if cmd.find('SOURCE_HOST') > -1:
+ cmd = re.sub(r"SOURCE_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
+
+ if cmd.find('MASTER_HOST') > -1:
+ cmd = re.sub(r"MASTER_HOST='(.*)'", "SOURCE_HOST='" + ip + "'", cmd, 1)
+
+ db.query(cmd)
+ uinfo = cmd_data['data']['info']
+ ps = uinfo['username'] + "|" + uinfo['password']
+ id_rsa_conn.where('ip=?', (ip,)).setField('ps', ps)
writeDbSyncStatus({'code': 4, 'msg': '刷新从库同步信息完成...', 'progress': 50})
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
root_dir = getServerDir()
msock = root_dir + "/mysql.sock"
+ mw.execShell("cd /tmp && gzip -d dump.sql.gz")
cmd = root_dir + "/bin/mysql -S " + msock + \
" -uroot -p" + pwd + " < /tmp/dump.sql"
import_data = mw.execShell(cmd)
- print(import_data[0])
- print(import_data[1])
if import_data[0] == '':
+ print(import_data[1])
writeDbSyncStatus({'code': 5, 'msg': '导入数据完成...', 'progress': 90})
else:
- writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 90})
+ print(import_data[0])
+ writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
return 'fail'
- db.query('start slave')
+ db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + SSH_PRIVATE_KEY)
@@ -1898,7 +2132,7 @@ def fullSync(version=''):
status_file = '/tmp/db_async_status.txt'
if args['begin'] == '1':
- cmd = 'cd ' + mw.getRunDir() + ' && python ' + \
+ cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
getPluginDir() + \
'/index.py do_full_sync {"db":"' + args['db'] + '"} &'
print(cmd)
@@ -1909,8 +2143,10 @@ def fullSync(version=''):
c = mw.readFile(status_file)
tmp = json.loads(c)
if tmp['code'] == 1:
- dump_size = os.path.getsize("/tmp/dump.sql")
- tmp['msg'] = tmp['msg'] + ":" + "同步文件:" + mw.toSize(dump_size)
+ sys_dump_sql = "/tmp/dump.sql"
+ if os.path.exists(sys_dump_sql):
+ dump_size = os.path.getsize(sys_dump_sql)
+ tmp['msg'] = tmp['msg'] + ":" + "同步文件:" + mw.toSize(dump_size)
c = json.dumps(tmp)
# if tmp['code'] == 6:
@@ -1926,12 +2162,18 @@ def installPreInspection(version):
return "为了稳定安装MariaDB,先安装swap插件!"
return 'ok'
+
+def uninstallPreInspection(version):
+ # return "请手动删除MySQL[{}]".format(version)
+ return 'ok'
+
if __name__ == "__main__":
func = sys.argv[1]
- version = "10.6"
- if (len(sys.argv) > 2):
- version = sys.argv[2]
+ version = "5.6"
+ version_pl = getServerDir() + "/version.pl"
+ if os.path.exists(version_pl):
+ version = mw.readFile(version_pl).strip()
if func == 'status':
print(status(version))
@@ -1949,6 +2191,8 @@ if __name__ == "__main__":
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
+ elif func == 'install_pre_inspection':
+ print(installPreInspection(version))
elif func == 'uninstall_pre_inspection':
print(uninstallPreInspection(version))
elif func == 'run_info':
@@ -1961,6 +2205,8 @@ if __name__ == "__main__":
print(getConf())
elif func == 'bin_log':
print(binLog())
+ elif func == 'clean_bin_log':
+ print(cleanBinLog())
elif func == 'error_log':
print(getErrorLog())
elif func == 'show_log':
@@ -1994,13 +2240,15 @@ if __name__ == "__main__":
elif func == 'sync_to_databases':
print(syncToDatabases())
elif func == 'set_root_pwd':
- print(setRootPwd())
+ print(setRootPwd(version))
elif func == 'set_user_pwd':
- print(setUserPwd())
+ print(setUserPwd(version))
elif func == 'get_db_access':
print(getDbAccess())
elif func == 'set_db_access':
print(setDbAccess())
+ elif func == 'get_db_rw':
+ print(setDbRw(version))
elif func == 'set_db_ps':
print(setDbPs())
elif func == 'get_db_info':
@@ -2013,5 +2261,57 @@ if __name__ == "__main__":
print(alterTable())
elif func == 'get_total_statistics':
print(getTotalStatistics())
+ elif func == 'get_dbrun_mode':
+ print(getDbrunMode(version))
+ elif func == 'set_dbrun_mode':
+ print(setDbrunMode(version))
+ elif func == 'get_masterdb_list':
+ print(getMasterDbList(version))
+ elif func == 'get_master_status':
+ print(getMasterStatus(version))
+ elif func == 'set_master_status':
+ print(setMasterStatus(version))
+ elif func == 'set_db_master':
+ print(setDbMaster(version))
+ elif func == 'set_db_slave':
+ print(setDbSlave(version))
+ elif func == 'set_dbmaster_access':
+ print(setDbMasterAccess())
+ elif func == 'get_master_rep_slave_list':
+ print(getMasterRepSlaveList(version))
+ elif func == 'add_master_rep_slave_user':
+ print(addMasterRepSlaveUser(version))
+ elif func == 'del_master_rep_slave_user':
+ print(delMasterRepSlaveUser(version))
+ elif func == 'update_master_rep_slave_user':
+ print(updateMasterRepSlaveUser(version))
+ elif func == 'get_master_rep_slave_user_cmd':
+ print(getMasterRepSlaveUserCmd(version))
+ elif func == 'get_slave_list':
+ print(getSlaveList(version))
+ elif func == 'get_slave_sync_cmd':
+ print(getSlaveSyncCmd(version))
+ elif func == 'get_slave_ssh_list':
+ print(getSlaveSSHList(version))
+ elif func == 'get_slave_ssh_by_ip':
+ print(getSlaveSSHByIp(version))
+ elif func == 'add_slave_ssh':
+ print(addSlaveSSH(version))
+ elif func == 'del_slave_ssh':
+ print(delSlaveSSH(version))
+ elif func == 'update_slave_ssh':
+ print(updateSlaveSSH(version))
+ elif func == 'init_slave_status':
+ print(initSlaveStatus(version))
+ elif func == 'set_slave_status':
+ print(setSlaveStatus(version))
+ elif func == 'delete_slave':
+ print(deleteSlave(version))
+ elif func == 'full_sync':
+ print(fullSync(version))
+ elif func == 'do_full_sync':
+ print(doFullSync(version))
+ elif func == 'dump_mysql_data':
+ print(dumpMysqlData(version))
else:
print('error')
diff --git a/plugins/mariadb/init.d/mariadb.tpl b/plugins/mariadb/init.d/mariadb.tpl
old mode 100755
new mode 100644
index c14f5ad3a..6a0a54174
--- a/plugins/mariadb/init.d/mariadb.tpl
+++ b/plugins/mariadb/init.d/mariadb.tpl
@@ -1,4 +1,8 @@
#!/bin/sh
+# chkconfig: 2345 55 25
+# Description: mysql service
+# distro. For CentOS/Redhat run: 'chkconfig --add mysql'
+
# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
# This file is public domain and comes with NO WARRANTY of any kind
@@ -25,7 +29,7 @@
# Description: MySQL is a very fast and reliable SQL database engine.
### END INIT INFO
-# If you install MySQL on some other places than /Users/midoks/Desktop/fwww/server/mysql, then you
+# If you install MySQL on some other places than /www/server/mysql, then you
# have to do one of the following things for this script to work:
#
# - Run this script from within the MySQL installation directory
@@ -110,7 +114,7 @@ mode=$1 # start or stop
[ $# -ge 1 ] && shift
-other_args="$*" # uncommon, but needed when called from an RPM upgrade action
+other_args=--sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" # uncommon, but needed when called from an RPM upgrade action
# Expected: "--skip-networking --skip-grant-tables"
# They are not checked here, intentionally, as it is the resposibility
# of the "spec" file author to give correct arguments only.
@@ -234,6 +238,11 @@ extra_args=""
if test -r "$basedir/my.cnf"
then
extra_args="-e $basedir/my.cnf"
+else
+ if test -r "$datadir/my.cnf"
+ then
+ extra_args="-e $datadir/my.cnf"
+ fi
fi
parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
@@ -241,9 +250,10 @@ parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server m
#
# Set pid file if not given
#
+found_pid=`cd $datadir && ls |grep '.pid'`
if test -z "$mysqld_pid_file_path"
then
- mysqld_pid_file_path=$datadir/`hostname`.pid
+ mysqld_pid_file_path=$datadir/$found_pid
else
case "$mysqld_pid_file_path" in
/* ) ;;
@@ -251,6 +261,7 @@ else
esac
fi
+#ulimit -s unlimited
case "$mode" in
'start')
# Start daemon
@@ -263,7 +274,7 @@ case "$mode" in
then
# Give extra arguments to mysqld with the my.cnf file. This script
# may be overwritten at next upgrade.
- $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null &
+ $bindir/mysqld_safe --defaults-file=$basedir/etc/my.cnf --datadir="$datadir" $other_args >/dev/null &
wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$?
# Make lock for RedHat / SuSE
@@ -284,9 +295,6 @@ case "$mode" in
if test -s "$mysqld_pid_file_path"
then
- # signal mysqld_safe that it needs to stop
- touch "$mysqld_pid_file_path.shutdown"
-
mysqld_pid=`cat "$mysqld_pid_file_path"`
if (kill -0 $mysqld_pid 2>/dev/null)
@@ -345,7 +353,7 @@ case "$mode" in
fi
else
# Try to find appropriate mysqld process
- mysqld_pid=`pgrep -d' ' -f $libexecdir/mysqld`
+ mysqld_pid=`pidof $libexecdir/mysqld`
# test if multiple pids exist
pid_count=`echo $mysqld_pid | wc -w`
diff --git a/plugins/mariadb/js/mariadb.js b/plugins/mariadb/js/mariadb.js
index 6873ffe08..d501726bc 100755
--- a/plugins/mariadb/js/mariadb.js
+++ b/plugins/mariadb/js/mariadb.js
@@ -49,7 +49,7 @@ function myPostN(method,args,callback, title){
if (typeof(title) != 'undefined'){
_title = title;
}
- $.post('/plugins/run', {name:'mariadb', func:method, args:_args}, function(data) {
+ $.post('/plugins/run', {name:'mysql', func:method, args:_args}, function(data) {
if(typeof(callback) == 'function'){
callback(data);
}
@@ -65,7 +65,7 @@ function myAsyncPost(method,args){
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
- return syncPost('/plugins/run', {name:'mariadb', func:method, args:_args});
+ return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
}
function runInfo(){
@@ -526,6 +526,17 @@ function checkSelect(){
},5)
}
+function setDbRw(id,username,val){
+ myPost('get_db_rw',{id:id,username:username,rw:val}, function(data){
+ var rdata = $.parseJSON(data.data);
+ // layer.msg(rdata.msg,{icon:rdata.status ? 1 : 5,shade: [0.3, '#000']});
+ showMsg(rdata.msg, function(){
+ dbList();
+ },{icon:rdata.status ? 1 : 5,shade: [0.3, '#000']}, 2000);
+
+ });
+}
+
function setDbAccess(username){
myPost('get_db_access','username='+username, function(data){
var rdata = $.parseJSON(data.data);
@@ -540,8 +551,9 @@ function setDbAccess(username){
title: '设置数据库权限',
closeBtn: 1,
shift: 5,
+ btn:["提交","取消"],
shadeClose: true,
- content: "
",
- });
-
- layer.ready(function(){
- if (rdata.msg == '127.0.0.1'){
- $('select[name="dataAccess"]').find("option[value='127.0.0.1']").attr("selected",true);
- } else if (rdata.msg == '%'){
- $('select[name="dataAccess"]').find('option[value="%"]').attr("selected",true);
- } else if ( rdata.msg == 'ip' ){
- $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
- $('select[name="dataAccess"]').after("
");
- } else {
- $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
- $('select[name="dataAccess"]').after("
");
- }
- });
-
- $('#my_mod_close').click(function(){
- $('.layui-layer-close1').click();
- });
-
-
- $('select[name="dataAccess"]').change(function(){
- var v = $(this).val();
- if (v == 'ip'){
- $(this).after("
");
- } else {
- $('#dataAccess_subid').remove();
- }
- });
+ success:function(){
+ if (rdata.msg == '127.0.0.1'){
+ $('select[name="dataAccess"]').find("option[value='127.0.0.1']").attr("selected",true);
+ } else if (rdata.msg == '%'){
+ $('select[name="dataAccess"]').find('option[value="%"]').attr("selected",true);
+ } else if ( rdata.msg == 'ip' ){
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ } else {
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ }
- $('#my_mod_save').click(function(){
- var data = $("#set_db_access").serialize();
- data = decodeURIComponent(data);
- var dataObj = str2Obj(data);
- if(!dataObj['access']){
- dataObj['access'] = dataObj['dataAccess'];
- if ( dataObj['dataAccess'] == 'ip'){
- if (dataObj['address']==''){
- layer.msg('IP地址不能空!',{icon:2,shade: [0.3, '#000']});
- return;
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#set_db_access").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['access']){
+ dataObj['access'] = dataObj['dataAccess'];
+ if ( dataObj['dataAccess'] == 'ip'){
+ if (dataObj['address']==''){
+ layer.msg('IP地址不能空!',{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ dataObj['access'] = dataObj['address'];
}
- dataObj['access'] = dataObj['address'];
}
+ dataObj['username'] = username;
+ myPost('set_db_access', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ dbList();
+ },{icon: rdata.status ? 1 : 2});
+ });
}
- dataObj['username'] = username;
- // console.log(data,dataObj);
- myPost('set_db_access', dataObj, function(data){
- var rdata = $.parseJSON(data.data);
- showMsg(rdata.msg,function(){
- dbList();
- $('.layui-layer-close1').click();
- },{icon: rdata.status ? 1 : 2});
- });
});
+
});
}
@@ -618,13 +619,13 @@ function setDbPass(id, username, password){
var index = layer.open({
type: 1,
- skin: 'demo-class',
area: '500px',
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
shadeClose: true,
- content: "
",
- });
-
- $('#my_mod_close').click(function(){
- $('.layui-layer-close1').click();
- });
-
- $('#my_mod_save').click(function(){
- var data = $("#mod_pwd").serialize();
- myPost('set_user_pwd', data, function(data){
- var rdata = $.parseJSON(data.data);
- showMsg(rdata.msg,function(){
- dbList();
- $('.layui-layer-close1').click();
- },{icon: rdata.status ? 1 : 2});
- });
+ yes:function(index){
+ var data = $("#mod_pwd").serialize();
+ myPost('set_user_pwd', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ dbList();
+ },{icon: rdata.status ? 1 : 2});
+ });
+ }
});
}
@@ -835,7 +827,7 @@ function openPhpmyadmin(name,username,password){
//检查版本
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'version'});
bigVer = data.data.split('.')[0]
- if (bigVer>=5){
+ if (bigVer>=4.5){
setTimeout(function(){
$("#toPHPMyAdmin").submit();
@@ -968,9 +960,28 @@ function dbList(page, search){
list += '
'+(rdata.data[i]['is_backup']?'备份':'未备份') +' | ';
+ var rw = '';
+ var rw_change = 'all';
+ if (typeof(rdata.data[i]['rw'])!='undefined'){
+ var rw_val = '读写';
+ if (rdata.data[i]['rw'] == 'all'){
+ rw_val = "所有";
+ rw_change = 'rw';
+ } else if (rdata.data[i]['rw'] == 'rw'){
+ rw_val = "读写";
+ rw_change = 'r';
+ } else if (rdata.data[i]['rw'] == 'r'){
+ rw_val = "只读";
+ rw_change = 'all';
+ }
+ rw = '
'+rw_val+' | ';
+ }
+
+
list += '
管理 | ' +
'
工具 | ' +
'
权限 | ' +
+ rw +
'
改密 | ' +
'
删除' +
'';
@@ -1001,8 +1012,8 @@ function dbList(page, search){
'+ list +'\
\
\
- \
+
\
+
\
同步选中\
同步所有\
从服务器获取\
@@ -1031,12 +1042,20 @@ function myLogs(){
myPost('bin_log', {status:1}, function(data){
var rdata = $.parseJSON(data.data);
+ var line_status = ""
+ if (rdata.status){
+ line_status = '
\
+
';
+ } else {
+ line_status = '
';
+ }
+
var limitCon = '
\
二进制日志 ' + toSize(rdata.msg) + '\
- \
-
错误日志
\
+ '+line_status+'\
+
错误日志
\
\
- '
+ ';
$(".soft-man-con").html(limitCon);
//设置二进制日志
@@ -1044,10 +1063,15 @@ function myLogs(){
myPost('bin_log', 'close=change', function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
-
- setTimeout(function(){
- myLogs();
- }, 2000);
+ setTimeout(function(){myLogs();}, 2000);
+ });
+ });
+
+ $(".clean-btn-bin").click(function () {
+ myPost('clean_bin_log', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){myLogs();}, 2000);
});
});
@@ -1056,10 +1080,7 @@ function myLogs(){
myPost('error_log', 'close=1', function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
-
- setTimeout(function(){
- myLogs();
- }, 2000);
+ setTimeout(function(){myLogs();}, 2000);
});
})
@@ -1071,7 +1092,7 @@ function myLogs(){
} else {
error_body = rdata.msg;
}
- $("#error_log").text(error_body);
+ $("#error_log").html(error_body);
var ob = document.getElementById('error_log');
ob.scrollTop = ob.scrollHeight;
});
@@ -1181,7 +1202,7 @@ function repTools(db_name, res){
layer.open({
type: 1,
- title: "MySQL工具箱【" + db_name + "】",
+ title: "MariaDB工具箱【" + db_name + "】",
area: ['780px', '580px'],
closeBtn: 2,
shadeClose: false,
@@ -1219,3 +1240,796 @@ function repTools(db_name, res){
});
}
+
+function setDbMaster(name){
+ myPost('set_db_master', {name:name}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ masterOrSlaveConf();
+ }, 2000);
+ });
+}
+
+
+function setDbSlave(name){
+ myPost('set_db_slave', {name:name}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ masterOrSlaveConf();
+ }, 2000);
+ });
+}
+
+
+function addMasterRepSlaveUser(){
+ layer.open({
+ type: 1,
+ area: '500px',
+ title: '添加同步账户',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["提交","取消"],
+ content: "
",
+ success:function(){
+ $("input[name='name']").keyup(function(){
+ var v = $(this).val();
+ $("input[name='db_user']").val(v);
+ $("input[name='ps']").val(v);
+ });
+
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#add_master").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['address']){
+ dataObj['address'] = dataObj['dataAccess'];
+ }
+
+ myPost('add_master_rep_slave_user', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ if (rdata.status){
+ getMasterRepSlaveList();
+ }
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ }
+ });
+}
+
+
+
+function updateMasterRepSlaveUser(username){
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '更新账户',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ content: "
",
+ });
+
+ $('#submit_update_master').click(function(){
+ var data = $("#update_master").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ myPost('update_master_rep_slave_user', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getMasterRepSlaveList();
+ }
+ $('.layui-layer-close1').click();
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ });
+}
+
+function getMasterRepSlaveUserCmd(username, db=''){
+ myPost('get_master_rep_slave_user_cmd', {username:username,db:db}, function(data){
+ var rdata = $.parseJSON(data.data);
+
+ if (!rdata['status']){
+ layer.msg(rdata['msg']);
+ return;
+ }
+
+ var cmd = rdata.data['cmd'];
+
+ var loadOpen = layer.open({
+ type: 1,
+ title: '同步命令',
+ area: '500px',
+ content:"
",
+ });
+
+
+ copyPass(cmd);
+ $('.class-copy-cmd').click(function(){
+ copyPass(cmd);
+ });
+ });
+}
+
+function delMasterRepSlaveUser(username){
+ myPost('del_master_rep_slave_user', {username:username}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg);
+
+ $('.layui-layer-close1').click();
+
+ setTimeout(function(){
+ getMasterRepSlaveList();
+ },1000);
+ });
+}
+
+
+function setDbMasterAccess(username){
+ myPost('get_db_access','username='+username, function(data){
+ var rdata = $.parseJSON(data.data);
+ if (!rdata.status){
+ layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '设置数据库权限',
+ closeBtn: 1,
+ shift: 5,
+ btn:["提交","取消"],
+ shadeClose: true,
+ content: "
",
+ success:function(){
+ if (rdata.msg == '127.0.0.1'){
+ $('select[name="dataAccess"]').find("option[value='127.0.0.1']").attr("selected",true);
+ } else if (rdata.msg == '%'){
+ $('select[name="dataAccess"]').find('option[value="%"]').attr("selected",true);
+ } else if ( rdata.msg == 'ip' ){
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ } else {
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ }
+
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#set_db_access").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['access']){
+ dataObj['access'] = dataObj['dataAccess'];
+ if ( dataObj['dataAccess'] == 'ip'){
+ if (dataObj['address']==''){
+ layer.msg('IP地址不能空!',{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ dataObj['access'] = dataObj['address'];
+ }
+ }
+ dataObj['username'] = username;
+ myPost('set_dbmaster_access', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ },{icon: rdata.status ? 1 : 2});
+ });
+ }
+ });
+
+ });
+}
+
+function getMasterRepSlaveList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+ myPost('get_master_rep_slave_list', _data, function(data){
+ // console.log(data);
+ var rdata = [];
+ try {
+ rdata = $.parseJSON(data.data);
+ } catch(e){
+ console.log(e);
+ }
+ var list = '';
+ // console.log(rdata['data']);
+ var user_list = rdata['data'];
+ for (i in user_list) {
+ // console.log(i);
+ var name = user_list[i]['username'];
+ list += '
'+name+' | \
+ '+user_list[i]['password']+' | \
+ \
+ 修改 | \
+ 删除 | \
+ 权限 | \
+ 从库同步命令\
+ | \
+
';
+ }
+
+ $('#get_master_rep_slave_list_page tbody').html(list);
+ $('.dataTables_paginate_4').html(rdata['page']);
+ });
+}
+
+function getMasterRepSlaveListPage(){
+ var page = '
';
+ page += '
添加同步账户
';
+
+ var loadOpen = layer.open({
+ type: 1,
+ title: '同步账户列表',
+ area: '500px',
+ content:"
",
+ success:function(){
+ getMasterRepSlaveList();
+ }
+ });
+}
+
+
+function deleteSlave(){
+ myPost('delete_slave', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata['msg'], function(){
+ masterOrSlaveConf();
+ },{},3000);
+ });
+}
+
+
+function getFullSyncStatus(db){
+ var timeId = null;
+
+ var btn = '
开始
';
+ var loadOpen = layer.open({
+ type: 1,
+ title: '全量同步['+db+']',
+ area: '500px',
+ content:"
",
+ cancel: function(){
+ clearInterval(timeId);
+ }
+ });
+
+ function fullSync(db,begin){
+
+ myPostN('full_sync', {db:db,begin:begin}, function(data){
+ var rdata = $.parseJSON(data.data);
+ $('#full_msg').text(rdata['msg']);
+ $('.progress-bar').css('width',rdata['progress']+'%');
+ $('.progress-bar').text(rdata['progress']+'%');
+
+ if (rdata['code']==6 ||rdata['code']<0){
+ layer.msg(rdata['msg']);
+ clearInterval(timeId);
+ $("#begin_full_sync").attr('data-status','init');
+ }
+ });
+ }
+
+ $('#begin_full_sync').click(function(){
+ var val = $(this).attr('data-status');
+ if (val == 'init'){
+ fullSync(db,1);
+ timeId = setInterval(function(){
+ fullSync(db,0);
+ }, 1000);
+ $(this).attr('data-status','starting');
+ } else {
+ layer.msg("正在同步中..");
+ }
+ });
+}
+
+function addSlaveSSH(ip=''){
+
+ myPost('get_slave_ssh_by_ip', {ip:ip}, function(rdata){
+
+ var rdata = $.parseJSON(rdata.data);
+
+ var ip = '127.0.0.1';
+ var port = "22";
+ var id_rsa = '';
+ var db_user ='';
+
+ if (rdata.data.length>0){
+ ip = rdata.data[0]['ip'];
+ port = rdata.data[0]['port'];
+ id_rsa = rdata.data[0]['id_rsa'];
+ db_user = rdata.data[0]['db_user'];
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: ['500px','480px'],
+ title: '添加SSH',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["确认","取消"],
+ content: "
",
+ success:function(){
+ $('textarea[name="id_rsa"]').html(id_rsa);
+ },
+ yes:function(index){
+ var ip = $('input[name="ip"]').val();
+ var port = $('input[name="port"]').val();
+ var db_user = $('input[name="db_user"]').val();
+ var id_rsa = $('textarea[name="id_rsa"]').val();
+
+ var data = {ip:ip,port:port,id_rsa:id_rsa,db_user:db_user};
+ myPost('add_slave_ssh', data, function(data){
+ layer.close(index);
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getSlaveSSHPage();
+ }
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ }
+ });
+ });
+}
+
+
+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();
+ });
+}
+
+function getSlaveSSHPage(page=1){
+ var _data = {};
+ _data['page'] = page;
+ _data['page_size'] = 5;
+ _data['tojs'] ='getSlaveSSHPage';
+ myPost('get_slave_ssh_list', _data, function(data){
+ var layerId = null;
+ var rdata = [];
+ try {
+ rdata = $.parseJSON(data.data);
+ } catch(e) {
+ console.log(e);
+ }
+ var list = '';
+ var ssh_list = rdata['data'];
+ for (i in ssh_list) {
+ var ip = ssh_list[i]['ip'];
+ var port = ssh_list[i]['port'];
+
+ var id_rsa = '未设置';
+ if ( ssh_list[i]['port'] != ''){
+ id_rsa = '已设置';
+ }
+
+ var db_user = '未设置';
+ if ( ssh_list[i]['db_user'] != ''){
+ db_user = ssh_list[i]['db_user'];
+ }
+
+ list += '
'+ip+' | \
+ '+port+' | \
+ '+db_user+' | \
+ '+id_rsa+' | \
+ \
+ 修改 | \
+ 删除\
+ | \
+
';
+ }
+
+ $('.get-slave-ssh-list tbody').html(list);
+ $('.dataTables_paginate_4').html(rdata['page']);
+ });
+}
+
+
+function getSlaveSSHList(page=1){
+
+ var page = '
';
+ page += '
添加SSH
';
+
+ layerId = layer.open({
+ type: 1,
+ title: 'SSH列表',
+ area: '500px',
+ content:"
",
+ success:function(){
+ getSlaveSSHPage(1);
+ }
+ });
+}
+
+function handlerRun(){
+ myPostN('get_slave_sync_cmd', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ var cmd = rdata['data'];
+ var loadOpen = layer.open({
+ type: 1,
+ title: '手动执行',
+ area: '500px',
+ content:"
",
+ });
+ copyPass(cmd);
+ $('.class-copy-cmd').click(function(){
+ copyPass(cmd);
+ });
+ });
+}
+
+function initSlaveStatus(){
+ myPost('init_slave_status', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ masterOrSlaveConf();
+ }
+ },{icon:rdata.status?1:2},2000);
+ });
+}
+
+function masterOrSlaveConf(version=''){
+
+ function getMasterDbList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+
+ myPost('get_masterdb_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+ list += '
';
+ list += '' + rdata.data[i]['name'] +' | ';
+ list += '' + (rdata.data[i]['master']?'是':'否') +' | ';
+ list += '' +
+ ''+(rdata.data[i]['master']?'退出':'加入')+' | ' +
+ '同步命令' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
\
+
\
+
\
+
\
+ 同步账户列表\
+
\
+
';
+
+ $(".table_master_list").html(con);
+ $('#databasePage').html(rdata.page);
+ });
+ }
+
+ function getAsyncMasterDbList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+
+ myPost('get_slave_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+
+ var v = rdata.data[i];
+ var status = "异常";
+ if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
+ status = "正常";
+ }
+
+ list += '
';
+ list += '' + rdata.data[i]['Master_Host'] +' | ';
+ list += '' + rdata.data[i]['Master_Port'] +' | ';
+ list += '' + rdata.data[i]['Master_User'] +' | ';
+ list += '' + rdata.data[i]['Master_Log_File'] +' | ';
+ list += '' + rdata.data[i]['Slave_IO_Running'] +' | ';
+ list += '' + rdata.data[i]['Slave_SQL_Running'] +' | ';
+ list += '' + status +' | ';
+ list += '' +
+ '删除' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
';
+
+ //
\
+ //
\
+ // 添加\
+ //
+ $(".table_slave_status_list").html(con);
+ });
+ }
+
+ function getAsyncDataList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+ myPost('get_masterdb_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+ list += '
';
+ list += '' + rdata.data[i]['name'] +' | ';
+ list += '' +
+ ''+(rdata.data[i]['slave']?'退出':'加入')+' | ' +
+ '同步' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
\
+
\
+
\
+
\
+ 手动命令\
+ 全量同步\
+
\
+
';
+
+ $(".table_slave_list").html(con);
+ $('#databasePage').html(rdata.page);
+ });
+ }
+
+
+
+ function getMasterStatus(){
+ myPost('get_master_status', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ // console.log('mode:',rdata.data);
+ var rdata = rdata.data;
+ var limitCon = '\
+
\
+ 主从同步模式\
+ \
+ \
+
\
+
\
+
\
+ Master[主]配置\
+ \
+
\
+
\
+ \
+
\
+
\
+ \
+
\
+ Slave[从]配置\
+ \
+ \
+ \
+
\
+
\
+ \
+
\
+ \
+
\
+ ';
+ $(".soft-man-con").html(limitCon);
+
+ //设置主服务器配置
+ $(".btn-master").click(function () {
+ myPost('set_master_status', 'close=change', function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ getMasterStatus();
+ }, 3000);
+ });
+ });
+
+ $(".btn-slave").click(function () {
+ myPost('set_slave_status', 'close=change', function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ getMasterStatus();
+ }, 3000);
+ });
+ });
+
+ $('.db-mode').click(function(){
+ if ($(this).hasClass('btn-success')){
+ //no action
+ return;
+ }
+
+ var mode = 'classic';
+ if ($(this).hasClass('btn-gtid')){
+ mode = 'gtid';
+ }
+
+ layer.open({
+ type:1,
+ title:"MySQL主从模式切换",
+ shadeClose:false,
+ btnAlign: 'c',
+ btn: ['切换并重启', '切换不重启'],
+ yes: function(index, layero){
+ this.change(index,mode,"yes");
+
+ },
+ btn2: function(index, layero){
+ this.change(index,mode,"no");
+ return false;
+ },
+ change:function(index,mode,reload){
+ console.log(index,mode,reload);
+ myPost('set_dbrun_mode',{'mode':mode,'reload':reload},function(data){
+ layer.close(index);
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg ,function(){
+ getMasterStatus();
+ },{ icon: rdata.status ? 1 : 5 });
+ });
+ }
+ });
+ });
+
+ if (rdata.status){
+ getMasterDbList();
+ }
+
+ if (rdata.slave_status){
+ getAsyncMasterDbList();
+ getAsyncDataList()
+ }
+ });
+ }
+ getMasterStatus();
+}
diff --git a/plugins/mariadb/scripts/backup.py b/plugins/mariadb/scripts/backup.py
new file mode 100755
index 000000000..21ef91d10
--- /dev/null
+++ b/plugins/mariadb/scripts/backup.py
@@ -0,0 +1,125 @@
+# coding: utf-8
+#-----------------------------
+# 网站备份工具
+#-----------------------------
+
+import sys
+import os
+
+if sys.platform != 'darwin':
+ os.chdir('/www/server/mdserver-web')
+
+
+chdir = os.getcwd()
+sys.path.append(chdir + '/class/core')
+
+# reload(sys)
+# sys.setdefaultencoding('utf-8')
+
+
+import mw
+import db
+import time
+
+
+class backupTools:
+
+ def backupDatabase(self, name, count):
+ db_path = mw.getServerDir() + '/mariadb'
+ db_name = 'mysql'
+ name = mw.M('databases').dbPos(db_path, 'mysql').where(
+ 'name=?', (name,)).getField('name')
+ startTime = time.time()
+ if not name:
+ endDate = time.strftime('%Y/%m/%d %X', time.localtime())
+ log = "数据库[" + name + "]不存在!"
+ print("★[" + endDate + "] " + log)
+ print(
+ "----------------------------------------------------------------------------")
+ return
+
+ backup_path = mw.getRootDir() + '/backup/database'
+ if not os.path.exists(backup_path):
+ mw.execShell("mkdir -p " + backup_path)
+
+ filename = backup_path + "/db_" + name + "_" + \
+ time.strftime('%Y%m%d_%H%M%S', time.localtime()) + ".sql.gz"
+
+ import re
+ mysql_root = mw.M('config').dbPos(db_path, db_name).where(
+ "id=?", (1,)).getField('mysql_root')
+
+ mycnf = mw.readFile(db_path + '/etc/my.cnf')
+ rep = "\[mysqldump\]\nuser=root"
+ sea = "[mysqldump]\n"
+ subStr = sea + "user=root\npassword=" + mysql_root + "\n"
+ mycnf = mycnf.replace(sea, subStr)
+ if len(mycnf) > 100:
+ mw.writeFile(db_path + '/etc/my.cnf', mycnf)
+
+ # mw.execShell(db_path + "/bin/mysqldump --opt --default-character-set=utf8 " +
+ # name + " | gzip > " + filename)
+
+ # mw.execShell(db_path + "/bin/mysqldump --skip-lock-tables --default-character-set=utf8 " +
+ # name + " | gzip > " + filename)
+
+ mw.execShell(db_path + "/bin/mysqldump --single-transaction --quick --default-character-set=utf8 " +
+ name + " | gzip > " + filename)
+
+ if not os.path.exists(filename):
+ endDate = time.strftime('%Y/%m/%d %X', time.localtime())
+ log = "数据库[" + name + "]备份失败!"
+ print("★[" + endDate + "] " + log)
+ print(
+ "----------------------------------------------------------------------------")
+ return
+
+ mycnf = mw.readFile(db_path + '/etc/my.cnf')
+ mycnf = mycnf.replace(subStr, sea)
+ if len(mycnf) > 100:
+ mw.writeFile(db_path + '/etc/my.cnf', mycnf)
+
+ endDate = time.strftime('%Y/%m/%d %X', time.localtime())
+ outTime = time.time() - startTime
+ pid = mw.M('databases').dbPos(db_path, db_name).where(
+ 'name=?', (name,)).getField('id')
+
+ mw.M('backup').add('type,name,pid,filename,addtime,size', (1, os.path.basename(
+ filename), pid, filename, endDate, os.path.getsize(filename)))
+ log = "数据库[" + name + "]备份成功,用时[" + str(round(outTime, 2)) + "]秒"
+ mw.writeLog('计划任务', log)
+ print("★[" + endDate + "] " + log)
+ print("|---保留最新的[" + count + "]份备份")
+ print("|---文件名:" + filename)
+
+ # 清理多余备份
+ backups = mw.M('backup').where(
+ 'type=? and pid=?', ('1', pid)).field('id,filename').select()
+
+ num = len(backups) - int(count)
+ if num > 0:
+ for backup in backups:
+ mw.execShell("rm -f " + backup['filename'])
+ mw.M('backup').where('id=?', (backup['id'],)).delete()
+ num -= 1
+ print("|---已清理过期备份文件:" + backup['filename'])
+ if num < 1:
+ break
+
+ def backupDatabaseAll(self, save):
+ db_path = mw.getServerDir() + '/mariadb'
+ db_name = 'mysql'
+ databases = mw.M('databases').dbPos(
+ db_path, db_name).field('name').select()
+ for database in databases:
+ self.backupDatabase(database['name'], save)
+
+
+if __name__ == "__main__":
+ backup = backupTools()
+ type = sys.argv[1]
+ if type == 'database':
+ if sys.argv[2] == 'ALL':
+ backup.backupDatabaseAll(sys.argv[3])
+ else:
+ backup.backupDatabase(sys.argv[2], sys.argv[3])
diff --git a/plugins/mariadb/versions/10.6/install.sh b/plugins/mariadb/versions/10.6/install.sh
index 70075fd69..8a0f55cf4 100755
--- a/plugins/mariadb/versions/10.6/install.sh
+++ b/plugins/mariadb/versions/10.6/install.sh
@@ -51,6 +51,10 @@ Install_app()
else
cpuCore="1"
fi
+
+ if [ "$cpuCore" -gt "1" ];then
+ cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
+ fi
# ----- cpu end ------
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
@@ -63,6 +67,11 @@ Install_app()
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
+ OPTIONS=''
+ if [ "$sysName" == "Darwin" ];then
+ OPTIONS='-DPLUGIN_TOKUDB=NO'
+ fi
+
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
@@ -75,6 +84,7 @@ Install_app()
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
+ $OPTIONS \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
diff --git a/plugins/mariadb/versions/10.7/install.sh b/plugins/mariadb/versions/10.7/install.sh
index b7a157592..ab3508dab 100755
--- a/plugins/mariadb/versions/10.7/install.sh
+++ b/plugins/mariadb/versions/10.7/install.sh
@@ -51,6 +51,10 @@ Install_app()
else
cpuCore="1"
fi
+
+ if [ "$cpuCore" -gt "1" ];then
+ cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
+ fi
# ----- cpu end ------
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
diff --git a/plugins/mariadb/versions/10.8/install.sh b/plugins/mariadb/versions/10.8/install.sh
index b3bee2bdc..8321b1fad 100755
--- a/plugins/mariadb/versions/10.8/install.sh
+++ b/plugins/mariadb/versions/10.8/install.sh
@@ -51,6 +51,10 @@ Install_app()
else
cpuCore="1"
fi
+
+ if [ "$cpuCore" -gt "1" ];then
+ cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
+ fi
# ----- cpu end ------
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
diff --git a/plugins/mysql/conf/classic.cnf b/plugins/mysql/conf/classic.cnf
new file mode 100644
index 000000000..e69de29bb
diff --git a/plugins/mysql/conf/gtid.cnf b/plugins/mysql/conf/gtid.cnf
new file mode 100644
index 000000000..5076776a6
--- /dev/null
+++ b/plugins/mysql/conf/gtid.cnf
@@ -0,0 +1,4 @@
+[mysqld]
+# SHOW GLOBAL VARIABLES LIKE '%gtid%'
+gtid_mode=ON
+enforce_gtid_consistency=ON
\ No newline at end of file
diff --git a/plugins/mysql/conf/my.cnf b/plugins/mysql/conf/my.cnf
index 369e55b28..48c5a89f6 100644
--- a/plugins/mysql/conf/my.cnf
+++ b/plugins/mysql/conf/my.cnf
@@ -5,6 +5,11 @@ port = 3306
socket = {$SERVER_APP_PATH}/mysql.sock
[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
@@ -12,9 +17,13 @@ socket = {$SERVER_APP_PATH}/mysql.sock
basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
-default_storage_engine = MyISAM
+server-id = {$SERVER_ID}
+
+default_storage_engine = InnoDB
+
key_buffer_size = 8M
max_allowed_packet = 100M
+
table_open_cache = 32
sort_buffer_size = 256K
net_buffer_length = 4K
@@ -22,7 +31,7 @@ read_buffer_size = 128K
read_rnd_buffer_size = 256K
myisam_sort_buffer_size = 4M
thread_cache_size = 4
-lower_case_table_names=1
+lower_case_table_names=0
query_cache_size = 4M
tmp_table_size = 8M
@@ -30,22 +39,21 @@ max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
+skip-name-resolve=1
+#skip-grant-tables
#skip-networking
-#skip-name-resolve
#skip-external-locking
#loose-skip-innodb
-#skip-grant-tables
-skip-ssl
-
log-bin=mysql-bin
binlog_format=mixed
-server-id = 1
-expire_logs_days = 10
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
-long_query_time=3
+long_query_time=10
#log_queries_not_using_indexes=on
+#log_slow_admin_statements=1
+#log_slow_slave_statements=1
+expire_logs_days=30
relay-log=mdserver
relay-log-index=mdserver
@@ -58,14 +66,15 @@ binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#slave
-log-slave-updates
+log-slave-updates = 1
+skip-slave-start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
-default_storage_engine = InnoDB
+
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
@@ -73,12 +82,13 @@ innodb_buffer_pool_size = 16M
innodb_additional_mem_pool_size = 2M
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
-innodb_flush_log_at_trx_commit = 1
+innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
innodb_write_io_threads = 1
innodb_file_per_table=1
+innodb_large_prefix = 1
secure-file-priv={$SERVER_APP_PATH}/tmp
diff --git a/plugins/mysql/conf/my5.7.cnf b/plugins/mysql/conf/my5.7.cnf
index 5053013b6..df79938ef 100644
--- a/plugins/mysql/conf/my5.7.cnf
+++ b/plugins/mysql/conf/my5.7.cnf
@@ -6,6 +6,11 @@ socket = {$SERVER_APP_PATH}/mysql.sock
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
@@ -13,7 +18,9 @@ socket = {$SERVER_APP_PATH}/mysql.sock
basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
-default_storage_engine = MyISAM
+server-id = {$SERVER_ID}
+
+default_storage_engine = InnoDB
key_buffer_size = 8M
table_open_cache = 32
@@ -32,20 +39,21 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
+skip_name_resolve = 1
+#skip-networking
#skip-external-locking
-#skip-grant-tables
#loose-skip-innodb
-#skip-networking
-#skip-name-resolve
-skip-ssl
+#skip-grant-tables
log-bin=mysql-bin
binlog_format=mixed
-server-id = 1
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
-long_query_time=3
-#log_queries_not_using_indexes=on
+long_query_time=10
+#log_queries_not_using_indexes=1
+#log_slow_admin_statements=1
+#log_slow_slave_statements=1
+expire_logs_days=30
relay-log=mdserver
relay-log-index=mdserver
@@ -58,26 +66,28 @@ binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#slave
-log-slave-updates
+log-slave-updates = 1
+skip-slave-start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
-default_storage_engine = InnoDB
+
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
innodb_buffer_pool_size = 16M
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
-innodb_flush_log_at_trx_commit = 1
+innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
innodb_write_io_threads = 1
-innodb_file_per_table=1
+innodb_file_per_table = 1
+innodb_large_prefix = 1
secure-file-priv={$SERVER_APP_PATH}/tmp
diff --git a/plugins/mysql/conf/my8.0.cnf b/plugins/mysql/conf/my8.0.cnf
index e1e82a44a..4dbaaab0a 100644
--- a/plugins/mysql/conf/my8.0.cnf
+++ b/plugins/mysql/conf/my8.0.cnf
@@ -6,7 +6,12 @@ socket = {$SERVER_APP_PATH}/mysql.sock
default-character-set = UTF8MB4
[mysqld]
-default_authentication_plugin=mysql_native_password
+!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
+
+sha256_password_private_key_path=mysql.pem
+sha256_password_public_key_path=mysql.pub
+authentication_policy=mysql_native_password
+
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 3306
@@ -14,7 +19,9 @@ socket = {$SERVER_APP_PATH}/mysql.sock
basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
-default_storage_engine = MyISAM
+server-id = {$SERVER_ID}
+
+default_storage_engine = InnoDB
key_buffer_size = 8M
table_open_cache = 32
@@ -33,21 +40,21 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
+skip_name_resolve = 1
+#skip-networking
#skip-external-locking
-#skip-grant-tables
#loose-skip-innodb
-#skip-networking
-#skip-name-resolve
-skip-ssl
-
+#skip-grant-tables
log-bin=mysql-bin
binlog_format=mixed
-server-id = 1
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
-long_query_time=3
-#log_queries_not_using_indexes=on
+long_query_time=10
+#log_queries_not_using_indexes=1
+#log_slow_admin_statements=1
+#log_slow_replica_statements=1
+binlog_expire_logs_seconds=2592000
relay-log=mdserver
relay-log-index=mdserver
@@ -60,27 +67,27 @@ binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#slave
-log_replica_updates
+log_replica_updates = 1
+skip_replica_start = 1
#replicate-do-db
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
-default_storage_engine = InnoDB
+
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
innodb_buffer_pool_size = 16M
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
-innodb_flush_log_at_trx_commit = 1
+innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
innodb_write_io_threads = 1
innodb_file_per_table=1
-binlog_expire_logs_seconds=2592000
secure-file-priv={$SERVER_APP_PATH}/tmp
diff --git a/plugins/mysql/conf/mysql.sql b/plugins/mysql/conf/mysql.sql
index c62fc5c94..f6df3e957 100755
--- a/plugins/mysql/conf/mysql.sql
+++ b/plugins/mysql/conf/mysql.sql
@@ -12,9 +12,11 @@ CREATE TABLE IF NOT EXISTS `databases` (
`username` TEXT,
`password` TEXT,
`accept` TEXT,
+ `rw` TEXT DEFAULT 'rw',
`ps` TEXT,
`addtime` TEXT
);
+-- ALTER TABLE `databases` ADD COLUMN `rw` TEXT DEFAULT 'rw';
CREATE TABLE IF NOT EXISTS `master_replication_user` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -32,6 +34,7 @@ CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
`ip` TEXT,
`port` TEXT,
`user` TEXT,
+ `db_user` TEXT,
`id_rsa` TEXT,
`ps` TEXT,
`addtime` TEXT
diff --git a/plugins/mysql/index.html b/plugins/mysql/index.html
index 78645b3b6..ee348dbdc 100755
--- a/plugins/mysql/index.html
+++ b/plugins/mysql/index.html
@@ -2,7 +2,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/plugins/postgresql/index.py b/plugins/postgresql/index.py
new file mode 100755
index 000000000..0a834c1fb
--- /dev/null
+++ b/plugins/postgresql/index.py
@@ -0,0 +1,724 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import subprocess
+import re
+import json
+
+
+# reload(sys)
+# sys.setdefaultencoding('utf-8')
+
+sys.path.append(os.getcwd() + "/class/core")
+import mw
+
+
+if mw.isAppleSystem():
+ cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
+ info = mw.execShell(cmd)
+ p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
+ sys.path.append(p)
+
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+def getPluginName():
+ return 'postgresql'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+def getInitDFile():
+ if app_debug:
+ return '/tmp/' + getPluginName()
+ return '/etc/init.d/' + getPluginName()
+
+
+def getArgs():
+ args = sys.argv[2:]
+
+ tmp = {}
+ args_len = len(args)
+
+ if args_len == 1:
+ t = args[0].strip('{').strip('}')
+ t = t.split(':')
+ tmp[t[0]] = t[1]
+ elif args_len > 1:
+ for i in range(len(args)):
+ t = args[i].split(':')
+ tmp[t[0]] = t[1]
+
+ return tmp
+
+
+def checkArgs(data, ck=[]):
+ for i in range(len(ck)):
+ if not ck[i] in data:
+ return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
+ return (True, mw.returnJson(True, 'ok'))
+
+
+def getConf():
+ path = getServerDir() + '/data/postgresql.conf'
+ return path
+
+
+def getDbPort():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'port\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def getSocketFile():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'socket\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def getInitdTpl(version=''):
+ path = getPluginDir() + '/init.d/postgresql.tpl'
+ if not os.path.exists(path):
+ path = getPluginDir() + '/init.d/postgresql.tpl'
+ return path
+
+
+def contentReplace(content):
+ service_path = mw.getServerDir()
+ content = content.replace('{$ROOT_PATH}', mw.getRootDir())
+ content = content.replace('{$SERVER_PATH}', service_path)
+ content = content.replace('{$APP_PATH}', service_path + '/postgresql')
+ return content
+
+
+def pSqliteDb(dbname='databases'):
+ file = getServerDir() + '/pgsql.db'
+ name = 'pgsql'
+ if not os.path.exists(file):
+ conn = mw.M(dbname).dbPos(getServerDir(), name)
+ csql = mw.readFile(getPluginDir() + '/conf/pgsql.sql')
+ csql_list = csql.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)
+ return conn
+
+
+def pMysqlDb():
+ # pymysql
+ db = mw.getMyORM()
+ # MySQLdb |
+ # db = mw.getMyORMDb()
+
+ db.setPort(getDbPort())
+ db.setSocket(getSocketFile())
+ # db.setCharset("utf8")
+ db.setPwd(pSqliteDb('config').where('id=?', (1,)).getField('mysql_root'))
+ return db
+
+
+def initDreplace(version=''):
+
+ conf_dir = getServerDir() + '/etc'
+ log_dir = getServerDir() + "/logs"
+ conf_list = [
+ conf_dir,
+ log_dir
+ ]
+ for c in conf_list:
+ if not os.path.exists(c):
+ os.mkdir(c)
+
+ # my_conf = conf_dir + '/my.cnf'
+ # if not os.path.exists(my_conf):
+ # tpl = getPluginDir() + '/conf/my.cnf'
+ # content = mw.readFile(tpl)
+ # content = contentReplace(content)
+ # mw.writeFile(my_conf, content)
+
+ # systemd
+ system_dir = mw.systemdCfgDir()
+ service = system_dir + '/postgresql.service'
+ if os.path.exists(system_dir) and not os.path.exists(service):
+ tpl = getPluginDir() + '/init.d/postgresql.service.tpl'
+ service_path = mw.getServerDir()
+ content = mw.readFile(tpl)
+ content = contentReplace(content)
+ mw.writeFile(service, content)
+ mw.execShell('systemctl daemon-reload')
+
+ if not mw.isAppleSystem():
+ mw.execShell('chown -R postgresql:postgresql ' + getServerDir())
+
+ initd_path = getServerDir() + '/init.d'
+ if not os.path.exists(initd_path):
+ os.mkdir(initd_path)
+
+ file_bin = initd_path + '/' + getPluginName()
+ if not os.path.exists(file_bin):
+ initd_tpl = getInitdTpl(version)
+ content = mw.readFile(initd_tpl)
+ content = contentReplace(content)
+ mw.writeFile(file_bin, content)
+ mw.execShell('chmod +x ' + file_bin)
+ return file_bin
+
+
+def status(version=''):
+ data = mw.execShell(
+ "ps -ef|grep postgres |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
+ if data[0] == '':
+ return 'stop'
+ return 'start'
+
+
+def getDataDir():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'datadir\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def getPidFile():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'pid-file\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def getErrorLog():
+ args = getArgs()
+ path = getDataDir()
+ filename = ''
+ for n in os.listdir(path):
+ if len(n) < 5:
+ continue
+ if n == 'error.log':
+ filename = path + '/' + n
+ break
+ # print filename
+ if not os.path.exists(filename):
+ return mw.returnJson(False, '指定文件不存在!')
+ if 'close' in args:
+ mw.writeFile(filename, '')
+ return mw.returnJson(False, '日志已清空')
+ info = mw.getNumLines(filename, 18)
+ return mw.returnJson(True, 'OK', info)
+
+
+def getShowLogFile():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'slow-query-log-file\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def pGetDbUser():
+ if mw.isAppleSystem():
+ user = mw.execShell(
+ "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
+ return user
+ return 'postgresql'
+
+
+def initPgData():
+ serverdir = getServerDir()
+ if not os.path.exists(serverdir + '/postgresql'):
+ cmd = 'cd ' + serverdir + ' && ./bin/initdb -D ' + serverdir + "/data"
+ mw.execShell(cmd)
+ return False
+ return True
+
+
+def initPgPwd():
+
+ serverdir = getServerDir()
+ pwd = mw.getRandomString(16)
+
+ cmd_pass = "echo \"create user root with superuser password '" + pwd + "'\" | "
+ cmd_pass = cmd_pass + serverdir + '/bin/psql -d postgres'
+ data = mw.execShell(cmd_pass)
+ print(cmd_pass)
+ print(data)
+
+ pSqliteDb('config').where('id=?', (1,)).save('pg_root', (pwd,))
+ return True
+
+
+def myOp(version, method):
+ # import commands
+ init_file = initDreplace()
+ cmd = init_file + ' ' + method
+ # print(cmd)
+ try:
+ isInited = initPgData()
+ if not isInited:
+ if mw.isAppleSystem():
+ cmd_init_start = init_file + ' start'
+ subprocess.Popen(cmd_init_start, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+
+ time.sleep(6)
+ else:
+ mw.execShell('systemctl start postgresql')
+
+ initPgPwd()
+
+ if mw.isAppleSystem():
+ cmd_init_stop = init_file + ' stop'
+ subprocess.Popen(cmd_init_stop, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+ time.sleep(3)
+ else:
+ mw.execShell('systemctl stop postgresql')
+
+ if mw.isAppleSystem():
+ sub = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
+ bufsize=4096, stderr=subprocess.PIPE)
+ sub.wait(5)
+ else:
+ mw.execShell('systemctl ' + method + ' postgresql')
+ return 'ok'
+ except Exception as e:
+ # raise
+ return method + ":" + str(e)
+
+
+def appCMD(version, action):
+ return myOp(version, action)
+
+
+def start(version=''):
+ return appCMD(version, 'start')
+
+
+def stop(version=''):
+ return appCMD(version, 'stop')
+
+
+def restart(version=''):
+ return appCMD(version, 'restart')
+
+
+def reload(version=''):
+ return appCMD(version, 'reload')
+
+
+def initdStatus():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+
+ shell_cmd = 'systemctl status postgresql | grep loaded | grep "enabled;"'
+ data = mw.execShell(shell_cmd)
+ if data[0] == '':
+ return 'fail'
+ return 'ok'
+
+
+def initdInstall():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+
+ mw.execShell('systemctl enable postgresql')
+ return 'ok'
+
+
+def initdUinstall():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+
+ mw.execShell('systemctl disable postgresql')
+ return 'ok'
+
+
+def getMyDbPos():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'datadir\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def setMyDbPos():
+ args = getArgs()
+ data = checkArgs(args, ['datadir'])
+ if not data[0]:
+ return data[1]
+
+ s_datadir = getMyDbPos()
+ t_datadir = args['datadir']
+ if t_datadir == s_datadir:
+ return mw.returnJson(False, '与当前存储目录相同,无法迁移文件!')
+
+ if not os.path.exists(t_datadir):
+ mw.execShell('mkdir -p ' + t_datadir)
+
+ # mw.execShell('/etc/init.d/mysqld stop')
+ stop()
+ mw.execShell('cp -rf ' + s_datadir + '/* ' + t_datadir + '/')
+ mw.execShell('chown -R mysql mysql ' + t_datadir)
+ mw.execShell('chmod -R 755 ' + t_datadir)
+ mw.execShell('rm -f ' + t_datadir + '/*.pid')
+ mw.execShell('rm -f ' + t_datadir + '/*.err')
+
+ path = getServerDir()
+ myfile = path + '/etc/my.cnf'
+ mycnf = mw.readFile(myfile)
+ mw.writeFile(path + '/etc/my_backup.cnf', mycnf)
+
+ mycnf = mycnf.replace(s_datadir, t_datadir)
+ mw.writeFile(myfile, mycnf)
+ start()
+
+ result = mw.execShell(
+ 'ps aux|grep mysqld| grep -v grep|grep -v python')
+ if len(result[0]) > 10:
+ mw.writeFile('data/datadir.pl', t_datadir)
+ return mw.returnJson(True, '存储目录迁移成功!')
+ else:
+ mw.execShell('pkill -9 mysqld')
+ mw.writeFile(myfile, mw.readFile(path + '/etc/my_backup.cnf'))
+ start()
+ return mw.returnJson(False, '文件迁移失败!')
+
+
+def getPgPort():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'port\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def setPgPort():
+ args = getArgs()
+ data = checkArgs(args, ['port'])
+ if not data[0]:
+ return data[1]
+
+ port = args['port']
+ file = getConf()
+ content = mw.readFile(file)
+ rep = "port\s*=\s*([0-9]+)\s*\n"
+ content = re.sub(rep, 'port = ' + port + '\n', content)
+ mw.writeFile(file, content)
+ restart()
+ return mw.returnJson(True, '编辑成功!')
+
+
+def runInfo():
+
+ if status(version) == 'stop':
+ return mw.returnJson(False, 'PG未启动', [])
+
+ db = pMysqlDb()
+ data = db.query('show global status')
+ gets = ['Max_used_connections', 'Com_commit', 'Com_rollback', 'Questions', 'Innodb_buffer_pool_reads', 'Innodb_buffer_pool_read_requests', 'Key_reads', 'Key_read_requests', 'Key_writes',
+ 'Key_write_requests', 'Qcache_hits', 'Qcache_inserts', 'Bytes_received', 'Bytes_sent', 'Aborted_clients', 'Aborted_connects',
+ 'Created_tmp_disk_tables', 'Created_tmp_tables', 'Innodb_buffer_pool_pages_dirty', 'Opened_files', 'Open_tables', 'Opened_tables', 'Select_full_join',
+ 'Select_range_check', 'Sort_merge_passes', 'Table_locks_waited', 'Threads_cached', 'Threads_connected', 'Threads_created', 'Threads_running', 'Connections', 'Uptime']
+
+ result = {}
+ # print(data)
+ for d in data:
+ vname = d["Variable_name"]
+ for g in gets:
+ if vname == g:
+ result[g] = d["Value"]
+
+ # print(result, int(result['Uptime']))
+ result['Run'] = int(time.time()) - int(result['Uptime'])
+ tmp = db.query('show master status')
+ try:
+ result['File'] = tmp[0]["File"]
+ result['Position'] = tmp[0]["Position"]
+ except:
+ result['File'] = 'OFF'
+ result['Position'] = 'OFF'
+ return mw.getJson(result)
+
+
+def runLog():
+ return getServerDir() + "/logs/server.log"
+
+
+def myDbStatus():
+ result = {}
+ db = pMysqlDb()
+ data = db.query('show variables')
+ isError = isSqlError(data)
+ if isError != None:
+ return isError
+
+ gets = ['table_open_cache', 'thread_cache_size', 'key_buffer_size', 'tmp_table_size', 'max_heap_table_size', 'innodb_buffer_pool_size',
+ 'innodb_additional_mem_pool_size', 'innodb_log_buffer_size', 'max_connections', 'sort_buffer_size', 'read_buffer_size', 'read_rnd_buffer_size', 'join_buffer_size', 'thread_stack', 'binlog_cache_size']
+ result['mem'] = {}
+ for d in data:
+ vname = d['Variable_name']
+ for g in gets:
+ # print(g)
+ if vname == g:
+ result['mem'][g] = d["Value"]
+ return mw.getJson(result)
+
+
+def setDbStatus():
+ gets = ['key_buffer_size', 'tmp_table_size', 'max_heap_table_size', 'innodb_buffer_pool_size', 'innodb_log_buffer_size', 'max_connections',
+ 'table_open_cache', 'thread_cache_size', 'sort_buffer_size', 'read_buffer_size', 'read_rnd_buffer_size', 'join_buffer_size', 'thread_stack', 'binlog_cache_size']
+ emptys = ['max_connections', 'thread_cache_size', 'table_open_cache']
+ args = getArgs()
+ conFile = getConf()
+ content = mw.readFile(conFile)
+ n = 0
+ for g in gets:
+ s = 'M'
+ if n > 5:
+ s = 'K'
+ if g in emptys:
+ s = ''
+ rep = '\s*' + g + '\s*=\s*\d+(M|K|k|m|G)?\n'
+ c = g + ' = ' + args[g] + s + '\n'
+ if content.find(g) != -1:
+ content = re.sub(rep, '\n' + c, content, 1)
+ else:
+ content = content.replace('[mysqld]\n', '[mysqld]\n' + c)
+ n += 1
+ mw.writeFile(conFile, content)
+ return mw.returnJson(True, '设置成功!')
+
+
+def __createUser(dbname, username, password, address):
+ pdb = pMysqlDb()
+
+ if username == 'root':
+ dbname = '*'
+
+ pdb.execute(
+ "CREATE USER `%s`@`localhost` IDENTIFIED BY '%s'" % (username, password))
+ pdb.execute(
+ "grant all privileges on %s.* to `%s`@`localhost`" % (dbname, username))
+ for a in address.split(','):
+ pdb.execute(
+ "CREATE USER `%s`@`%s` IDENTIFIED BY '%s'" % (username, a, password))
+ pdb.execute(
+ "grant all privileges on %s.* to `%s`@`%s`" % (dbname, username, a))
+ pdb.execute("flush privileges")
+
+
+def getDbBackupListFunc(dbname=''):
+ bkDir = mw.getRootDir() + '/backup/database'
+ blist = os.listdir(bkDir)
+ r = []
+
+ bname = 'db_' + dbname
+ blen = len(bname)
+ for x in blist:
+ fbstr = x[0:blen]
+ if fbstr == bname:
+ r.append(x)
+ return r
+
+
+def setDbBackup():
+ args = getArgs()
+ data = checkArgs(args, ['name'])
+ if not data[0]:
+ return data[1]
+
+ scDir = getPluginDir() + '/scripts/backup.py'
+ cmd = 'python3 ' + scDir + ' database ' + args['name'] + ' 3'
+ os.system(cmd)
+ return mw.returnJson(True, 'ok')
+
+
+def importDbBackup():
+ args = getArgs()
+ data = checkArgs(args, ['file', 'name'])
+ if not data[0]:
+ return data[1]
+
+ file = args['file']
+ name = args['name']
+
+ file_path = mw.getRootDir() + '/backup/database/' + file
+ file_path_sql = mw.getRootDir() + '/backup/database/' + file.replace('.gz', '')
+
+ if not os.path.exists(file_path_sql):
+ cmd = 'cd ' + mw.getRootDir() + '/backup/database && gzip -d ' + file
+ mw.execShell(cmd)
+
+ pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
+
+ mysql_cmd = mw.getRootDir() + '/server/mysql/bin/mysql -uroot -p' + pwd + \
+ ' ' + name + ' < ' + file_path_sql
+
+ # print(mysql_cmd)
+ os.system(mysql_cmd)
+ return mw.returnJson(True, 'ok')
+
+
+def deleteDbBackup():
+ args = getArgs()
+ data = checkArgs(args, ['filename'])
+ if not data[0]:
+ return data[1]
+
+ bkDir = mw.getRootDir() + '/backup/database'
+
+ os.remove(bkDir + '/' + args['filename'])
+ return mw.returnJson(True, 'ok')
+
+
+def getDbBackupList():
+ args = getArgs()
+ data = checkArgs(args, ['name'])
+ if not data[0]:
+ return data[1]
+
+ r = getDbBackupListFunc(args['name'])
+ bkDir = mw.getRootDir() + '/backup/database'
+ rr = []
+ for x in range(0, len(r)):
+ p = bkDir + '/' + r[x]
+ data = {}
+ data['name'] = r[x]
+
+ rsize = os.path.getsize(p)
+ data['size'] = mw.toSize(rsize)
+
+ t = os.path.getctime(p)
+ t = time.localtime(t)
+
+ data['time'] = time.strftime('%Y-%m-%d %H:%M:%S', t)
+ rr.append(data)
+
+ data['file'] = p
+
+ return mw.returnJson(True, 'ok', rr)
+
+
+def getDbList():
+ args = getArgs()
+ page = 1
+ page_size = 10
+ search = ''
+ data = {}
+ if 'page' in args:
+ page = int(args['page'])
+
+ if 'page_size' in args:
+ page_size = int(args['page_size'])
+
+ if 'search' in args:
+ search = args['search']
+
+ conn = pSqliteDb('databases')
+ limit = str((page - 1) * page_size) + ',' + str(page_size)
+ condition = ''
+ if not search == '':
+ condition = "name like '%" + search + "%'"
+ field = 'id,pid,name,username,password,accept,rw,ps,addtime'
+ clist = conn.where(condition, ()).field(
+ field).limit(limit).order('id desc').select()
+
+ for x in range(0, len(clist)):
+ dbname = clist[x]['name']
+ blist = getDbBackupListFunc(dbname)
+ # print(blist)
+ clist[x]['is_backup'] = False
+ if len(blist) > 0:
+ clist[x]['is_backup'] = True
+
+ count = conn.where(condition, ()).count()
+ _page = {}
+ _page['count'] = count
+ _page['p'] = page
+ _page['row'] = page_size
+ _page['tojs'] = 'dbList'
+ data['page'] = mw.getPage(_page)
+ data['data'] = clist
+
+ info = {}
+ info['root_pwd'] = pSqliteDb('config').where(
+ 'id=?', (1,)).getField('mysql_root')
+ data['info'] = info
+
+ return mw.getJson(data)
+
+
+def installPreInspection(version):
+ return 'ok'
+
+
+def uninstallPreInspection(version):
+ # return "请手动删除MySQL[{}]".format(version)
+ return 'ok'
+
+if __name__ == "__main__":
+ func = sys.argv[1]
+
+ version = "14.4"
+ version_pl = getServerDir() + "/version.pl"
+ if os.path.exists(version_pl):
+ version = mw.readFile(version_pl).strip()
+
+ if func == 'status':
+ print(status(version))
+ elif func == 'start':
+ print(start(version))
+ elif func == 'stop':
+ print(stop(version))
+ elif func == 'restart':
+ print(restart(version))
+ elif func == 'reload':
+ print(reload(version))
+ elif func == 'initd_status':
+ print(initdStatus())
+ elif func == 'initd_install':
+ print(initdInstall())
+ elif func == 'initd_uninstall':
+ print(initdUinstall())
+ elif func == 'install_pre_inspection':
+ print(installPreInspection(version))
+ elif func == 'uninstall_pre_inspection':
+ print(uninstallPreInspection(version))
+ elif func == 'conf':
+ print(getConf())
+ elif func == 'run_info':
+ print(runInfo())
+ elif func == 'run_log':
+ print(runLog())
+ elif func == 'pg_port':
+ print(getPgPort())
+ elif func == 'set_pg_port':
+ print(setPgPort())
+ elif func == 'get_db_list':
+ print(getDbList())
+ else:
+ print('error')
diff --git a/plugins/postgresql/info.json b/plugins/postgresql/info.json
new file mode 100755
index 000000000..342f924d8
--- /dev/null
+++ b/plugins/postgresql/info.json
@@ -0,0 +1,18 @@
+{
+ "title":"PostgreSQL",
+ "tip":"soft",
+ "name":"postgresql",
+ "type":"运行环境",
+ "ps":"[DEV]功能强大的开源数据库",
+ "coexist": false,
+ "install_pre_inspection":true,
+ "uninstall_pre_inspection":true,
+ "versions":["14.4"],
+ "shell":"install.sh",
+ "checks":"server/postgresql",
+ "path":"server/postgresql",
+ "author":"postgresql",
+ "home":"https://www.postgresql.org/",
+ "date":"2022-08-07",
+ "pid": "2"
+}
\ No newline at end of file
diff --git a/plugins/postgresql/init.d/postgresql.service.tpl b/plugins/postgresql/init.d/postgresql.service.tpl
new file mode 100644
index 000000000..fd856395a
--- /dev/null
+++ b/plugins/postgresql/init.d/postgresql.service.tpl
@@ -0,0 +1,16 @@
+[Unit]
+Description=PostgreSQL: a powerful open source database
+After=network.target
+
+[Service]
+Type=forking
+User=postgres
+Group=postgres
+WorkingDirectory={$APP_PATH}
+ExecStart={$APP_PATH}/pg_ctl start -D {$APP_PATH}/data
+ExecReload={$APP_PATH}/pg_ctl restart -D {$APP_PATH}/data
+ExecStop={$APP_PATH}/pg_ctl stop -D {$APP_PATH}/data
+PrivateTmp=false
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/plugins/postgresql/init.d/postgresql.tpl b/plugins/postgresql/init.d/postgresql.tpl
new file mode 100644
index 000000000..a0c5cf3db
--- /dev/null
+++ b/plugins/postgresql/init.d/postgresql.tpl
@@ -0,0 +1,66 @@
+#!/bin/bash
+# chkconfig: 2345 55 25
+# description: PostgreSQL Service
+
+### BEGIN INIT INFO
+# Provides: Midoks
+# Required-Start: $all
+# Required-Stop: $all
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: starts PostgreSQL
+# Description: starts the PostgreSQL
+### END INIT INFO
+
+
+PATH=/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
+export LC_ALL="en_US.UTF-8"
+
+MW_PATH={$SERVER_PATH}
+PATH=$PATH:$MW_PATH/bin
+
+if [ -f $MW_PATH/bin/activate ];then
+ source $MW_PATH/bin/activate
+fi
+
+pg_start()
+{
+ touch {$APP_PATH}/logs/server.log
+ {$APP_PATH}/bin/pg_ctl -D {$APP_PATH}/data -l {$APP_PATH}/logs/server.log start
+}
+
+
+pg_stop()
+{
+ {$APP_PATH}/bin/pg_ctl -D {$APP_PATH}/data -l {$APP_PATH}/logs/server.log stop
+}
+
+
+
+pg_status()
+{
+ isStart=$(ps aux |grep 'postgres'|grep -v grep|awk '{print $2}')
+ if [ "$isStart" != '' ];then
+ echo -e "\033[32mPostgreSQL (pid $isStart) already running\033[0m"
+ else
+ echo -e "\033[31mPostgreSQL not running\033[0m"
+ fi
+}
+
+
+pg_reload()
+{
+ pg_stop
+ pg_start
+}
+
+
+
+case "$1" in
+ 'start') pg_start;;
+ 'stop') pg_stop;;
+ 'reload') pg_reload;;
+ 'restart')
+ pg_stop
+ pg_start;;
+esac
diff --git a/plugins/postgresql/install.sh b/plugins/postgresql/install.sh
new file mode 100755
index 000000000..741fc3540
--- /dev/null
+++ b/plugins/postgresql/install.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
+export PATH
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+
+
+install_tmp=${rootPath}/tmp/mw_install.pl
+
+action=$1
+type=$2
+
+if [ "${2}" == "" ];then
+ echo '缺少安装脚本...' > $install_tmp
+ exit 0
+fi
+
+if [ ! -d $curPath/versions/$2 ];then
+ echo '缺少安装脚本2...' > $install_tmp
+ exit 0
+fi
+
+# if [ "${action}" == "uninstall" ];then
+# if [ -f /usr/lib/systemd/system/postgresql.service ] || [ -f /lib/systemd/system/postgresql.service ];then
+# systemctl stop postgresql
+# systemctl disable postgresql
+# rm -rf /usr/lib/systemd/system/postgresql.service
+# rm -rf /lib/systemd/system/postgresql.service
+# systemctl daemon-reload
+# fi
+# fi
+
+sh -x $curPath/versions/$2/install.sh $1
+
+# if [ "${action}" == "install" ] && [ -d $serverPath/postgresql ];then
+# #初始化
+# cd ${rootPath} && python3 ${rootPath}/plugins/postgresql/index.py start ${type}
+# cd ${rootPath} && python3 ${rootPath}/plugins/postgresql/index.py initd_install ${type}
+# fi
diff --git a/plugins/postgresql/js/postgresql.js b/plugins/postgresql/js/postgresql.js
new file mode 100755
index 000000000..ad71f3468
--- /dev/null
+++ b/plugins/postgresql/js/postgresql.js
@@ -0,0 +1,1969 @@
+function str2Obj(str){
+ var data = {};
+ kv = str.split('&');
+ for(i in kv){
+ v = kv[i].split('=');
+ data[v[0]] = v[1];
+ }
+ return data;
+}
+
+function myPost(method,args,callback, title){
+
+ var _args = null;
+ if (typeof(args) == 'string'){
+ _args = JSON.stringify(str2Obj(args));
+ } else {
+ _args = JSON.stringify(args);
+ }
+
+ var _title = '正在获取...';
+ if (typeof(title) != 'undefined'){
+ _title = title;
+ }
+
+ var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 });
+ $.post('/plugins/run', {name:'postgresql', func:method, args:_args}, function(data) {
+ layer.close(loadT);
+ if (!data.status){
+ layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
+ return;
+ }
+
+ if(typeof(callback) == 'function'){
+ callback(data);
+ }
+ },'json');
+}
+
+function myPostN(method,args,callback, title){
+
+ var _args = null;
+ if (typeof(args) == 'string'){
+ _args = JSON.stringify(str2Obj(args));
+ } else {
+ _args = JSON.stringify(args);
+ }
+
+ var _title = '正在获取...';
+ if (typeof(title) != 'undefined'){
+ _title = title;
+ }
+ $.post('/plugins/run', {name:'postgresql', func:method, args:_args}, function(data) {
+ if(typeof(callback) == 'function'){
+ callback(data);
+ }
+ },'json');
+}
+
+function myAsyncPost(method,args){
+ var _args = null;
+ if (typeof(args) == 'string'){
+ _args = JSON.stringify(str2Obj(args));
+ } else {
+ _args = JSON.stringify(args);
+ }
+
+ var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
+ return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
+}
+
+function runInfo(){
+ myPost('run_info','',function(data){
+
+ var rdata = $.parseJSON(data.data);
+ if (typeof(rdata['status']) != 'undefined'){
+ layer.msg(rdata['msg'],{icon:0,time:2000,shade: [0.3, '#000']});
+ return;
+ }
+
+ var cache_size = ((parseInt(rdata.Qcache_hits) / (parseInt(rdata.Qcache_hits) + parseInt(rdata.Qcache_inserts))) * 100).toFixed(2) + '%';
+ if (cache_size == 'NaN%') cache_size = 'OFF';
+ var Con = '
\
+ \
+ 启动时间 | ' + getLocalTime(rdata.Run) + ' | 每秒查询 | ' + parseInt(rdata.Questions / rdata.Uptime) + ' |
\
+ 总连接次数 | ' + rdata.Connections + ' | 每秒事务 | ' + parseInt((parseInt(rdata.Com_commit) + parseInt(rdata.Com_rollback)) / rdata.Uptime) + ' |
\
+ 发送 | ' + toSize(rdata.Bytes_sent) + ' | File | ' + rdata.File + ' |
\
+ 接收 | ' + toSize(rdata.Bytes_received) + ' | Position | ' + rdata.Position + ' |
\
+ \
+
\
+
\
+ | | | | \
+ \
+ 活动/峰值连接数 | ' + rdata.Threads_running + '/' + rdata.Max_used_connections + ' | 若值过大,增加max_connections |
\
+ 线程缓存命中率 | ' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '% | 若过低,增加thread_cache_size |
\
+ 索引命中率 | ' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '% | 若过低,增加key_buffer_size |
\
+ Innodb索引命中率 | ' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '% | 若过低,增加innodb_buffer_pool_size |
\
+ 查询缓存命中率 | ' + cache_size + ' | ' + lan.soft.mysql_status_ps5 + ' |
\
+ 创建临时表到磁盘 | ' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '% | 若过大,尝试增加tmp_table_size |
\
+ 已打开的表 | ' + rdata.Open_tables + ' | 若过大,增加table_cache_size |
\
+ 没有使用索引的量 | ' + rdata.Select_full_join + ' | 若不为0,请检查数据表的索引是否合理 |
\
+ 没有索引的JOIN量 | ' + rdata.Select_range_check + ' | 若不为0,请检查数据表的索引是否合理 |
\
+ 排序后的合并次数 | ' + rdata.Sort_merge_passes + ' | 若值过大,增加sort_buffer_size |
\
+ 锁表次数 | ' + rdata.Table_locks_waited + ' | 若值过大,请考虑增加您的数据库性能 |
\
+ \
+
';
+ $(".soft-man-con").html(Con);
+ });
+}
+
+
+function myDbPos(){
+ myPost('my_db_pos','',function(data){
+ var con = '
';
+ $(".soft-man-con").html(con);
+
+ $('#btn_change_path').click(function(){
+ var datadir = $("input[name='datadir']").val();
+ myPost('set_db_pos','datadir='+datadir,function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg,{icon:rdata.status ? 1 : 5,time:2000,shade: [0.3, '#000']});
+ });
+ });
+ });
+}
+
+function pgPort(){
+ myPost('pg_port','',function(data){
+ var con = '
';
+ $(".soft-man-con").html(con);
+
+ $('#btn_change_port').click(function(){
+ var port = $("input[name='port']").val();
+ myPost('set_pg_port','port='+port,function(data){
+ var rdata = $.parseJSON(data.data);
+ if (rdata.status){
+ layer.msg('修改成功!',{icon:1,time:2000,shade: [0.3, '#000']});
+ } else {
+ layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
+ }
+ });
+ });
+ });
+}
+
+
+//数据库存储信置
+function changeMySQLDataPath(act) {
+ if (act != undefined) {
+ layer.confirm(lan.soft.mysql_to_msg, { closeBtn: 2, icon: 3 }, function() {
+ var datadir = $("#datadir").val();
+ var data = 'datadir=' + datadir;
+ var loadT = layer.msg(lan.soft.mysql_to_msg1, { icon: 16, time: 0, shade: [0.3, '#000'] });
+ $.post('/database?action=SetDataDir', data, function(rdata) {
+ layer.close(loadT)
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ });
+ });
+ return;
+ }
+
+ $.post('/database?action=GetMySQLInfo', '', function(rdata) {
+ var LimitCon = '
\
+ \
+ \
+
';
+ $(".soft-man-con").html(LimitCon);
+ });
+}
+
+
+
+
+//数据库配置状态
+function myPerfOpt() {
+ //获取MySQL配置
+ myPost('db_status','',function(data){
+ var rdata = $.parseJSON(data.data);
+ // console.log(rdata);
+ var key_buffer_size = toSizeM(rdata.mem.key_buffer_size);
+ var query_cache_size = toSizeM(rdata.mem.query_cache_size);
+ var tmp_table_size = toSizeM(rdata.mem.tmp_table_size);
+ var innodb_buffer_pool_size = toSizeM(rdata.mem.innodb_buffer_pool_size);
+ var innodb_additional_mem_pool_size = toSizeM(rdata.mem.innodb_additional_mem_pool_size);
+ var innodb_log_buffer_size = toSizeM(rdata.mem.innodb_log_buffer_size);
+
+ var sort_buffer_size = toSizeM(rdata.mem.sort_buffer_size);
+ var read_buffer_size = toSizeM(rdata.mem.read_buffer_size);
+ var read_rnd_buffer_size = toSizeM(rdata.mem.read_rnd_buffer_size);
+ var join_buffer_size = toSizeM(rdata.mem.join_buffer_size);
+ var thread_stack = toSizeM(rdata.mem.thread_stack);
+ var binlog_cache_size = toSizeM(rdata.mem.binlog_cache_size);
+
+ var a = key_buffer_size + query_cache_size + tmp_table_size + innodb_buffer_pool_size + innodb_additional_mem_pool_size + innodb_log_buffer_size;
+ var b = sort_buffer_size + read_buffer_size + read_rnd_buffer_size + join_buffer_size + thread_stack + binlog_cache_size;
+ var memSize = a + rdata.mem.max_connections * b;
+
+
+ var memCon = '
\
+
最大使用内存: \
+ \
+ ' + lan.soft.mysql_set_maxmem + ': MB\
+
\
+
key_buffer_sizeMB, ' + lan.soft.mysql_set_key_buffer_size + '
\
+
query_cache_sizeMB, ' + lan.soft.mysql_set_query_cache_size + '
\
+
tmp_table_sizeMB, ' + lan.soft.mysql_set_tmp_table_size + '
\
+
innodb_buffer_pool_sizeMB, ' + lan.soft.mysql_set_innodb_buffer_pool_size + '
\
+
innodb_log_buffer_sizeMB, ' + lan.soft.mysql_set_innodb_log_buffer_size + '
\
+
innodb_additional_mem_pool_sizeMB
\
+
sort_buffer_sizeKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_sort_buffer_size + '
\
+
read_buffer_sizeKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_read_buffer_size + '
\
+
read_rnd_buffer_sizeKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_read_rnd_buffer_size + '
\
+
join_buffer_sizeKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_join_buffer_size + '
\
+
thread_stackKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_thread_stack + '
\
+
binlog_cache_sizeKB * ' + lan.soft.mysql_set_conn + ', ' + lan.soft.mysql_set_binlog_cache_size + '
\
+
thread_cache_size ' + lan.soft.mysql_set_thread_cache_size + '
\
+
table_open_cache ' + lan.soft.mysql_set_table_open_cache + '
\
+
max_connections ' + lan.soft.mysql_set_max_connections + '
\
+
\
+
'
+
+ $(".soft-man-con").html(memCon);
+
+ $(".conf_p input[name*='size'],.conf_p input[name='max_connections'],.conf_p input[name='thread_stack']").change(function() {
+ comMySqlMem();
+ });
+
+ $(".conf_p select[name='mysql_set']").change(function() {
+ mySQLMemOpt($(this).val());
+ comMySqlMem();
+ });
+ });
+}
+
+function reBootMySqld(){
+ pluginOpService('mysql','restart','');
+}
+
+
+//设置MySQL配置参数
+function setMySQLConf() {
+ $.post('/system/system_total', '', function(memInfo) {
+ var memSize = memInfo['memTotal'];
+ var setSize = parseInt($("input[name='memSize']").val());
+
+ if(memSize < setSize){
+ var errMsg = "错误,内存分配过高!
物理内存: {1}MB
最大使用内存: {2}MB
可能造成的后果: 导致数据库不稳定,甚至无法启动MySQLd服务!";
+ var msg = errMsg.replace('{1}',memSize).replace('{2}',setSize);
+ layer.msg(msg,{icon:2,time:5000});
+ return;
+ }
+
+ var query_cache_size = parseInt($("input[name='query_cache_size']").val());
+ var query_cache_type = 0;
+ if (query_cache_size > 0) {
+ query_cache_type = 1;
+ }
+ var data = {
+ key_buffer_size: parseInt($("input[name='key_buffer_size']").val()),
+ query_cache_size: query_cache_size,
+ query_cache_type: query_cache_type,
+ tmp_table_size: parseInt($("input[name='tmp_table_size']").val()),
+ max_heap_table_size: parseInt($("input[name='tmp_table_size']").val()),
+ innodb_buffer_pool_size: parseInt($("input[name='innodb_buffer_pool_size']").val()),
+ innodb_log_buffer_size: parseInt($("input[name='innodb_log_buffer_size']").val()),
+ sort_buffer_size: parseInt($("input[name='sort_buffer_size']").val()),
+ read_buffer_size: parseInt($("input[name='read_buffer_size']").val()),
+ read_rnd_buffer_size: parseInt($("input[name='read_rnd_buffer_size']").val()),
+ join_buffer_size: parseInt($("input[name='join_buffer_size']").val()),
+ thread_stack: parseInt($("input[name='thread_stack']").val()),
+ binlog_cache_size: parseInt($("input[name='binlog_cache_size']").val()),
+ thread_cache_size: parseInt($("input[name='thread_cache_size']").val()),
+ table_open_cache: parseInt($("input[name='table_open_cache']").val()),
+ max_connections: parseInt($("input[name='max_connections']").val())
+ };
+
+ myPost('set_db_status', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ reBootMySqld();
+ },{ icon: rdata.status ? 1 : 2 });
+ });
+ },'json');
+}
+
+
+//MySQL内存优化方案
+function mySQLMemOpt(opt) {
+ var query_size = parseInt($("input[name='query_cache_size']").val());
+ switch (opt) {
+ case '0':
+ $("input[name='key_buffer_size']").val(8);
+ if (query_size) $("input[name='query_cache_size']").val(4);
+ $("input[name='tmp_table_size']").val(8);
+ $("input[name='innodb_buffer_pool_size']").val(16);
+ $("input[name='sort_buffer_size']").val(256);
+ $("input[name='read_buffer_size']").val(256);
+ $("input[name='read_rnd_buffer_size']").val(128);
+ $("input[name='join_buffer_size']").val(128);
+ $("input[name='thread_stack']").val(256);
+ $("input[name='binlog_cache_size']").val(32);
+ $("input[name='thread_cache_size']").val(4);
+ $("input[name='table_open_cache']").val(32);
+ $("input[name='max_connections']").val(500);
+ break;
+ case '1':
+ $("input[name='key_buffer_size']").val(128);
+ if (query_size) $("input[name='query_cache_size']").val(64);
+ $("input[name='tmp_table_size']").val(64);
+ $("input[name='innodb_buffer_pool_size']").val(256);
+ $("input[name='sort_buffer_size']").val(768);
+ $("input[name='read_buffer_size']").val(768);
+ $("input[name='read_rnd_buffer_size']").val(512);
+ $("input[name='join_buffer_size']").val(1024);
+ $("input[name='thread_stack']").val(256);
+ $("input[name='binlog_cache_size']").val(64);
+ $("input[name='thread_cache_size']").val(64);
+ $("input[name='table_open_cache']").val(128);
+ $("input[name='max_connections']").val(100);
+ break;
+ case '2':
+ $("input[name='key_buffer_size']").val(256);
+ if (query_size) $("input[name='query_cache_size']").val(128);
+ $("input[name='tmp_table_size']").val(384);
+ $("input[name='innodb_buffer_pool_size']").val(384);
+ $("input[name='sort_buffer_size']").val(768);
+ $("input[name='read_buffer_size']").val(768);
+ $("input[name='read_rnd_buffer_size']").val(512);
+ $("input[name='join_buffer_size']").val(2048);
+ $("input[name='thread_stack']").val(256);
+ $("input[name='binlog_cache_size']").val(64);
+ $("input[name='thread_cache_size']").val(96);
+ $("input[name='table_open_cache']").val(192);
+ $("input[name='max_connections']").val(200);
+ break;
+ case '3':
+ $("input[name='key_buffer_size']").val(384);
+ if (query_size) $("input[name='query_cache_size']").val(192);
+ $("input[name='tmp_table_size']").val(512);
+ $("input[name='innodb_buffer_pool_size']").val(512);
+ $("input[name='sort_buffer_size']").val(1024);
+ $("input[name='read_buffer_size']").val(1024);
+ $("input[name='read_rnd_buffer_size']").val(768);
+ $("input[name='join_buffer_size']").val(2048);
+ $("input[name='thread_stack']").val(256);
+ $("input[name='binlog_cache_size']").val(128);
+ $("input[name='thread_cache_size']").val(128);
+ $("input[name='table_open_cache']").val(384);
+ $("input[name='max_connections']").val(300);
+ break;
+ case '4':
+ $("input[name='key_buffer_size']").val(512);
+ if (query_size) $("input[name='query_cache_size']").val(256);
+ $("input[name='tmp_table_size']").val(1024);
+ $("input[name='innodb_buffer_pool_size']").val(1024);
+ $("input[name='sort_buffer_size']").val(2048);
+ $("input[name='read_buffer_size']").val(2048);
+ $("input[name='read_rnd_buffer_size']").val(1024);
+ $("input[name='join_buffer_size']").val(4096);
+ $("input[name='thread_stack']").val(384);
+ $("input[name='binlog_cache_size']").val(192);
+ $("input[name='thread_cache_size']").val(192);
+ $("input[name='table_open_cache']").val(1024);
+ $("input[name='max_connections']").val(400);
+ break;
+ case '5':
+ $("input[name='key_buffer_size']").val(1024);
+ if (query_size) $("input[name='query_cache_size']").val(384);
+ $("input[name='tmp_table_size']").val(2048);
+ $("input[name='innodb_buffer_pool_size']").val(4096);
+ $("input[name='sort_buffer_size']").val(4096);
+ $("input[name='read_buffer_size']").val(4096);
+ $("input[name='read_rnd_buffer_size']").val(2048);
+ $("input[name='join_buffer_size']").val(8192);
+ $("input[name='thread_stack']").val(512);
+ $("input[name='binlog_cache_size']").val(256);
+ $("input[name='thread_cache_size']").val(256);
+ $("input[name='table_open_cache']").val(2048);
+ $("input[name='max_connections']").val(500);
+ break;
+ }
+}
+
+//计算MySQL内存开销
+function comMySqlMem() {
+ var key_buffer_size = parseInt($("input[name='key_buffer_size']").val());
+ var query_cache_size = parseInt($("input[name='query_cache_size']").val());
+ var tmp_table_size = parseInt($("input[name='tmp_table_size']").val());
+ var innodb_buffer_pool_size = parseInt($("input[name='innodb_buffer_pool_size']").val());
+ var innodb_additional_mem_pool_size = parseInt($("input[name='innodb_additional_mem_pool_size']").val());
+ var innodb_log_buffer_size = parseInt($("input[name='innodb_log_buffer_size']").val());
+
+ var sort_buffer_size = $("input[name='sort_buffer_size']").val() / 1024;
+ var read_buffer_size = $("input[name='read_buffer_size']").val() / 1024;
+ var read_rnd_buffer_size = $("input[name='read_rnd_buffer_size']").val() / 1024;
+ var join_buffer_size = $("input[name='join_buffer_size']").val() / 1024;
+ var thread_stack = $("input[name='thread_stack']").val() / 1024;
+ var binlog_cache_size = $("input[name='binlog_cache_size']").val() / 1024;
+ var max_connections = $("input[name='max_connections']").val();
+
+ var a = key_buffer_size + query_cache_size + tmp_table_size + innodb_buffer_pool_size + innodb_additional_mem_pool_size + innodb_log_buffer_size
+ var b = sort_buffer_size + read_buffer_size + read_rnd_buffer_size + join_buffer_size + thread_stack + binlog_cache_size
+ var memSize = a + max_connections * b
+ $("input[name='memSize']").val(memSize.toFixed(2));
+}
+
+function syncGetDatabase(){
+ myPost('sync_get_databases', null, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ dbList();
+ },{ icon: rdata.status ? 1 : 2 });
+ });
+}
+
+function syncToDatabase(type){
+ var data = [];
+ $('input[type="checkbox"].check:checked').each(function () {
+ if (!isNaN($(this).val())) data.push($(this).val());
+ });
+ var postData = 'type='+type+'&ids='+JSON.stringify(data);
+ myPost('sync_to_databases', postData, function(data){
+ var rdata = $.parseJSON(data.data);
+ // console.log(rdata);
+ showMsg(rdata.msg,function(){
+ dbList();
+ },{ icon: rdata.status ? 1 : 2 });
+ });
+}
+
+function setRootPwd(type, pwd){
+ if (type==1){
+ var data = $("#mod_pwd").serialize();
+ myPost('set_root_pwd', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ // console.log(rdata);
+ showMsg(rdata.msg,function(){
+ dbList();
+ $('.layui-layer-close1').click();
+ },{icon: rdata.status ? 1 : 2});
+ });
+ return;
+ }
+
+ var index = layer.open({
+ type: 1,
+ skin: 'demo-class',
+ area: '500px',
+ title: '修改数据库密码',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ content: "
",
+ });
+
+ $('#my_mod_close').click(function(){
+ $('.layui-layer-close1').click();
+ });
+}
+
+function showHidePass(obj){
+ var a = "glyphicon-eye-open";
+ var b = "glyphicon-eye-close";
+
+ if($(obj).hasClass(a)){
+ $(obj).removeClass(a).addClass(b);
+ $(obj).prev().text($(obj).prev().attr('data-pw'))
+ }
+ else{
+ $(obj).removeClass(b).addClass(a);
+ $(obj).prev().text('***');
+ }
+}
+
+function copyPass(password){
+ var clipboard = new ClipboardJS('#bt_copys');
+ clipboard.on('success', function (e) {
+ layer.msg('复制成功',{icon:1,time:2000});
+ });
+
+ clipboard.on('error', function (e) {
+ layer.msg('复制失败,浏览器不兼容!',{icon:2,time:2000});
+ });
+ $("#bt_copys").attr('data-clipboard-text',password);
+ $("#bt_copys").click();
+}
+
+function checkSelect(){
+ setTimeout(function () {
+ var num = $('input[type="checkbox"].check:checked').length;
+ // console.log(num);
+ if (num == 1) {
+ $('button[batch="true"]').hide();
+ $('button[batch="false"]').show();
+ }else if (num>1){
+ $('button[batch="true"]').show();
+ $('button[batch="false"]').show();
+ }else{
+ $('button[batch="true"]').hide();
+ $('button[batch="false"]').hide();
+ }
+ },5)
+}
+
+function setDbRw(id,username,val){
+ myPost('get_db_rw',{id:id,username:username,rw:val}, function(data){
+ var rdata = $.parseJSON(data.data);
+ // layer.msg(rdata.msg,{icon:rdata.status ? 1 : 5,shade: [0.3, '#000']});
+ showMsg(rdata.msg, function(){
+ dbList();
+ },{icon:rdata.status ? 1 : 5,shade: [0.3, '#000']}, 2000);
+
+ });
+}
+
+function setDbAccess(username){
+ myPost('get_db_access','username='+username, function(data){
+ var rdata = $.parseJSON(data.data);
+ if (!rdata.status){
+ layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '设置数据库权限',
+ closeBtn: 1,
+ shift: 5,
+ btn:["提交","取消"],
+ shadeClose: true,
+ content: "
",
+ success:function(){
+ if (rdata.msg == '127.0.0.1'){
+ $('select[name="dataAccess"]').find("option[value='127.0.0.1']").attr("selected",true);
+ } else if (rdata.msg == '%'){
+ $('select[name="dataAccess"]').find('option[value="%"]').attr("selected",true);
+ } else if ( rdata.msg == 'ip' ){
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ } else {
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ }
+
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#set_db_access").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['access']){
+ dataObj['access'] = dataObj['dataAccess'];
+ if ( dataObj['dataAccess'] == 'ip'){
+ if (dataObj['address']==''){
+ layer.msg('IP地址不能空!',{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ dataObj['access'] = dataObj['address'];
+ }
+ }
+ dataObj['username'] = username;
+ myPost('set_db_access', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ dbList();
+ },{icon: rdata.status ? 1 : 2});
+ });
+ }
+ });
+
+ });
+}
+
+function setDbPass(id, username, password){
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '修改数据库密码',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["提交","关闭"],
+ content: "
",
+ yes:function(index){
+ var data = $("#mod_pwd").serialize();
+ myPost('set_user_pwd', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ dbList();
+ },{icon: rdata.status ? 1 : 2});
+ });
+ }
+ });
+}
+
+function addDatabase(type){
+ if (type==1){
+ var data = $("#add_db").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['address']){
+ dataObj['address'] = dataObj['dataAccess'];
+ }
+ myPost('add_db', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ dbList();
+ }
+ $('.layui-layer-close1').click();
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ return;
+ }
+ var index = layer.open({
+ type: 1,
+ skin: 'demo-class',
+ area: '500px',
+ title: '添加数据库',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ content: "
",
+ });
+
+ $("input[name='name']").keyup(function(){
+ var v = $(this).val();
+ $("input[name='db_user']").val(v);
+ $("input[name='ps']").val(v);
+ });
+
+ $('#my_mod_close').click(function(){
+ $('.layui-layer-close1').click();
+ });
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+}
+
+function delDb(id, name){
+ safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
+ var data='id='+id+'&name='+name
+ myPost('del_db', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ dbList();
+ $('.layui-layer-close1').click();
+ },{icon: rdata.status ? 1 : 2}, 600);
+ });
+ });
+}
+
+function delDbBatch(){
+ var arr = [];
+ $('input[type="checkbox"].check:checked').each(function () {
+ var _val = $(this).val();
+ var _name = $(this).parent().next().text();
+ if (!isNaN(_val)) {
+ arr.push({'id':_val,'name':_name});
+ }
+ });
+
+ safeMessage('批量删除数据库','
您共选择了[2]个数据库,删除后将无法恢复,真的要删除吗?',function(){
+ var i = 0;
+ $(arr).each(function(){
+ var data = myAsyncPost('del_db', this);
+ var rdata = $.parseJSON(data.data);
+ if (!rdata.status){
+ layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
+ }
+ i++;
+ });
+
+ var msg = '成功删除['+i+']个数据库!';
+ showMsg(msg,function(){
+ dbList();
+ },{icon: 1}, 600);
+ });
+}
+
+
+function setDbPs(id, name, obj) {
+ var _span = $(obj);
+ var _input = $("
");
+ _span.hide().after(_input);
+ _input.focus();
+ _input.blur(function(){
+ $(this).remove();
+ var ps = _input.val();
+ _span.text(ps).show();
+ var data = {name:name,id:id,ps:ps};
+ myPost('set_db_ps', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+ });
+ _input.keyup(function(){
+ if(event.keyCode == 13){
+ _input.trigger('blur');
+ }
+ });
+}
+
+function openPhpmyadmin(name,username,password){
+
+ data = syncPost('/plugins/check',{'name':'phpmyadmin'});
+
+
+ if (!data.status){
+ layer.msg(data.msg,{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+
+ data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'status'});
+ if (data.data != 'start'){
+ layer.msg('phpMyAdmin未启动',{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ // console.log(data);
+ data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_home_page'});
+ var rdata = $.parseJSON(data.data);
+ if (!rdata.status){
+ layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ $("#toPHPMyAdmin").attr('action',rdata.data);
+
+ if($("#toPHPMyAdmin").attr('action').indexOf('phpmyadmin') == -1){
+ layer.msg('请先安装phpMyAdmin',{icon:2,shade: [0.3, '#000']});
+ setTimeout(function(){ window.location.href = '/soft'; },3000);
+ return;
+ }
+
+ //检查版本
+ data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'version'});
+ bigVer = data.data.split('.')[0]
+ if (bigVer>=4.5){
+
+ setTimeout(function(){
+ $("#toPHPMyAdmin").submit();
+ },3000);
+ layer.msg('phpMyAdmin['+data.data+']需要手动登录😭',{icon:16,shade: [0.3, '#000'],time:4000});
+
+ } else{
+ var murl = $("#toPHPMyAdmin").attr('action');
+ $("#pma_username").val(username);
+ $("#pma_password").val(password);
+ $("#db").val(name);
+
+ layer.msg('正在打开phpMyAdmin',{icon:16,shade: [0.3, '#000'],time:2000});
+
+ setTimeout(function(){
+ $("#toPHPMyAdmin").submit();
+ },3000);
+ }
+}
+
+function delBackup(filename,name){
+ myPost('delete_db_backup',{filename:filename},function(){
+ layer.msg('执行成功!');
+ setTimeout(function(){
+ $('.layui-layer-close2').click();
+ setBackup(name);
+ },2000);
+ });
+}
+
+function downloadBackup(file){
+ window.open('/files/download?filename='+encodeURIComponent(file));
+}
+
+function importBackup(file,name){
+ myPost('import_db_backup',{file:file,name:name}, function(data){
+ // console.log(data);
+ layer.msg('执行成功!');
+ });
+}
+
+function setBackup(db_name,obj){
+ myPost('get_db_backup_list', {name:db_name}, function(data){
+
+ var rdata = $.parseJSON(data.data);
+ var tbody = '';
+ for (var i = 0; i < rdata.data.length; i++) {
+ tbody += '
\
+ ' + rdata.data[i]['name'] + ' | \
+ ' + rdata.data[i]['size'] + ' | \
+ ' + rdata.data[i]['time'] + ' | \
+ \
+ 导入 | \
+ 下载 | \
+ 删除\
+ | \
+
';
+ }
+
+ var s = layer.open({
+ type: 1,
+ title: "数据库备份详情",
+ area: ['600px', '280px'],
+ closeBtn: 2,
+ shadeClose: false,
+ content: '
\
+
\
+ \
+
\
+
\
+
\
+
\
+ \
+ \
+ 文件名称 | \
+ 文件大小 | \
+ 备份时间 | \
+ 操作 | \
+
\
+ \
+ ' + tbody + '\
+
\
+
\
+
\
+
'
+ });
+
+ $('#btn_backup').click(function(){
+ myPost('set_db_backup',{name:db_name}, function(data){
+ layer.msg('执行成功!');
+
+ setTimeout(function(){
+ layer.close(s);
+ setBackup(db_name,obj);
+ },2000);
+ });
+ });
+ });
+}
+
+
+function dbList(page, search){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+ if(typeof(search) != 'undefined'){
+ _data['search'] = search;
+ }
+ myPost('get_db_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+ list += '
';
+ list +=' | ';
+ list += '' + rdata.data[i]['name'] +' | ';
+ list += '' + rdata.data[i]['username'] +' | ';
+ list += '' +
+ '***' +
+ ''+
+ ''+
+ ' | ';
+
+
+ list += ''+rdata.data[i]['ps']+' | ';
+ list += '';
+
+ list += ''+(rdata.data[i]['is_backup']?'备份':'未备份') +' | ';
+
+ var rw = '';
+ var rw_change = 'all';
+ if (typeof(rdata.data[i]['rw'])!='undefined'){
+ var rw_val = '读写';
+ if (rdata.data[i]['rw'] == 'all'){
+ rw_val = "所有";
+ rw_change = 'rw';
+ } else if (rdata.data[i]['rw'] == 'rw'){
+ rw_val = "读写";
+ rw_change = 'r';
+ } else if (rdata.data[i]['rw'] == 'r'){
+ rw_val = "只读";
+ rw_change = 'all';
+ }
+ rw = ''+rw_val+' | ';
+ }
+
+
+ list += '工具 | ' +
+ '权限 | ' +
+ rw +
+ '改密 | ' +
+ '删除' +
+ ' | ';
+ list += '
';
+ }
+
+ //
+ var con = '
\
+
\
+
\
+
\
+
\
+ \
+ \
+
\
+
\
+
\
+
\
+ 同步选中\
+ 同步所有\
+ 从服务器获取\
+
\
+
\
+
';
+
+ con += '
';
+
+ $(".soft-man-con").html(con);
+ $('#databasePage').html(rdata.page);
+
+ readerTableChecked();
+ });
+}
+
+function repCheckeds(tables) {
+ var dbs = []
+ if (tables) {
+ dbs.push(tables)
+ } else {
+ var db_tools = $("input[value^='dbtools_']");
+ for (var i = 0; i < db_tools.length; i++) {
+ if (db_tools[i].checked) dbs.push(db_tools[i].value.replace('dbtools_', ''));
+ }
+ }
+
+ if (dbs.length < 1) {
+ layer.msg('请至少选择一张表!', { icon: 2 });
+ return false;
+ }
+ return dbs;
+}
+
+function repDatabase(db_name, tables) {
+ dbs = repCheckeds(tables);
+
+ myPost('repair_table', { db_name: db_name, tables: JSON.stringify(dbs) }, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ repTools(db_name, true);
+ },'已送修复指令,请稍候...');
+}
+
+
+function optDatabase(db_name, tables) {
+ dbs = repCheckeds(tables);
+
+ myPost('opt_table', { db_name: db_name, tables: JSON.stringify(dbs) }, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ repTools(db_name, true);
+ },'已送优化指令,请稍候...');
+}
+
+function toDatabaseType(db_name, tables, type){
+ dbs = repCheckeds(tables);
+ myPost('alter_table', { db_name: db_name, tables: JSON.stringify(dbs),table_type: type }, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ repTools(db_name, true);
+ }, '已送引擎转换指令,请稍候...');
+}
+
+
+function selectedTools(my_obj, db_name) {
+ var is_checked = false
+
+ if (my_obj) is_checked = my_obj.checked;
+ var db_tools = $("input[value^='dbtools_']");
+ var n = 0;
+ for (var i = 0; i < db_tools.length; i++) {
+ if (my_obj) db_tools[i].checked = is_checked;
+ if (db_tools[i].checked) n++;
+ }
+ if (n > 0) {
+ var my_btns = '
\
+
\
+
\
+
'
+ $("#db_tools").html(my_btns);
+ } else {
+ $("#db_tools").html('');
+ }
+}
+
+function repTools(db_name, res){
+ myPost('get_db_info', {name:db_name}, function(data){
+ var rdata = $.parseJSON(data.data);
+ var types = { InnoDB: "MyISAM", MyISAM: "InnoDB" };
+ var tbody = '';
+ for (var i = 0; i < rdata.tables.length; i++) {
+ if (!types[rdata.tables[i].type]) continue;
+ tbody += '
\
+ | \
+ ' + rdata.tables[i].table_name + ' | \
+ ' + rdata.tables[i].type + ' | \
+ ' + rdata.tables[i].collation + ' | \
+ ' + rdata.tables[i].rows_count + ' | \
+ ' + rdata.tables[i].data_size + ' | \
+ \
+ 修复 |\
+ 优化 |\
+ 转为' + types[rdata.tables[i].type] + '\
+ | \
+
'
+ }
+
+ if (res) {
+ $(".gztr").html(tbody);
+ $("#db_tools").html('');
+ $("input[type='checkbox']").attr("checked", false);
+ $(".tools_size").html('大小:' + rdata.data_size);
+ return;
+ }
+
+ layer.open({
+ type: 1,
+ title: "MySQL工具箱【" + db_name + "】",
+ area: ['780px', '580px'],
+ closeBtn: 2,
+ shadeClose: false,
+ content: '
\
+
\
+
\
+
\
+ - 【修复】尝试使用REPAIR命令修复损坏的表,仅能做简单修复,若修复不成功请考虑使用myisamchk工具
\
+ - 【优化】执行OPTIMIZE命令,可回收未释放的磁盘空间,建议每月执行一次
\
+ - 【转为InnoDB/MyISAM】转换数据表引擎,建议将所有表转为InnoDB
\
+
'
+ });
+ tableFixed('database_fix');
+ });
+}
+
+
+function setDbMaster(name){
+ myPost('set_db_master', {name:name}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ masterOrSlaveConf();
+ }, 2000);
+ });
+}
+
+
+function setDbSlave(name){
+ myPost('set_db_slave', {name:name}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ masterOrSlaveConf();
+ }, 2000);
+ });
+}
+
+
+function addMasterRepSlaveUser(){
+ layer.open({
+ type: 1,
+ area: '500px',
+ title: '添加同步账户',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["提交","取消"],
+ content: "
",
+ success:function(){
+ $("input[name='name']").keyup(function(){
+ var v = $(this).val();
+ $("input[name='db_user']").val(v);
+ $("input[name='ps']").val(v);
+ });
+
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#add_master").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['address']){
+ dataObj['address'] = dataObj['dataAccess'];
+ }
+
+ myPost('add_master_rep_slave_user', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ if (rdata.status){
+ getMasterRepSlaveList();
+ }
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ }
+ });
+}
+
+
+
+function updateMasterRepSlaveUser(username){
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '更新账户',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ content: "
",
+ });
+
+ $('#submit_update_master').click(function(){
+ var data = $("#update_master").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ myPost('update_master_rep_slave_user', data, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getMasterRepSlaveList();
+ }
+ $('.layui-layer-close1').click();
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ });
+}
+
+function getMasterRepSlaveUserCmd(username, db=''){
+ myPost('get_master_rep_slave_user_cmd', {username:username,db:db}, function(data){
+ var rdata = $.parseJSON(data.data);
+
+ if (!rdata['status']){
+ layer.msg(rdata['msg']);
+ return;
+ }
+
+ var cmd = rdata.data['cmd'];
+
+ var loadOpen = layer.open({
+ type: 1,
+ title: '同步命令',
+ area: '500px',
+ content:"
",
+ });
+
+
+ copyPass(cmd);
+ $('.class-copy-cmd').click(function(){
+ copyPass(cmd);
+ });
+ });
+}
+
+function delMasterRepSlaveUser(username){
+ myPost('del_master_rep_slave_user', {username:username}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg);
+
+ $('.layui-layer-close1').click();
+
+ setTimeout(function(){
+ getMasterRepSlaveList();
+ },1000);
+ });
+}
+
+
+function setDbMasterAccess(username){
+ myPost('get_db_access','username='+username, function(data){
+ var rdata = $.parseJSON(data.data);
+ if (!rdata.status){
+ layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: '500px',
+ title: '设置数据库权限',
+ closeBtn: 1,
+ shift: 5,
+ btn:["提交","取消"],
+ shadeClose: true,
+ content: "
",
+ success:function(){
+ if (rdata.msg == '127.0.0.1'){
+ $('select[name="dataAccess"]').find("option[value='127.0.0.1']").attr("selected",true);
+ } else if (rdata.msg == '%'){
+ $('select[name="dataAccess"]').find('option[value="%"]').attr("selected",true);
+ } else if ( rdata.msg == 'ip' ){
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ } else {
+ $('select[name="dataAccess"]').find('option[value="ip"]').attr("selected",true);
+ $('select[name="dataAccess"]').after("
");
+ }
+
+ $('select[name="dataAccess"]').change(function(){
+ var v = $(this).val();
+ if (v == 'ip'){
+ $(this).after("
");
+ } else {
+ $('#dataAccess_subid').remove();
+ }
+ });
+ },
+ yes:function(index){
+ var data = $("#set_db_access").serialize();
+ data = decodeURIComponent(data);
+ var dataObj = str2Obj(data);
+ if(!dataObj['access']){
+ dataObj['access'] = dataObj['dataAccess'];
+ if ( dataObj['dataAccess'] == 'ip'){
+ if (dataObj['address']==''){
+ layer.msg('IP地址不能空!',{icon:2,shade: [0.3, '#000']});
+ return;
+ }
+ dataObj['access'] = dataObj['address'];
+ }
+ }
+ dataObj['username'] = username;
+ myPost('set_dbmaster_access', dataObj, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ layer.close(index);
+ },{icon: rdata.status ? 1 : 2});
+ });
+ }
+ });
+
+ });
+}
+
+function getMasterRepSlaveList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+ myPost('get_master_rep_slave_list', _data, function(data){
+ // console.log(data);
+ var rdata = [];
+ try {
+ rdata = $.parseJSON(data.data);
+ } catch(e){
+ console.log(e);
+ }
+ var list = '';
+ // console.log(rdata['data']);
+ var user_list = rdata['data'];
+ for (i in user_list) {
+ // console.log(i);
+ var name = user_list[i]['username'];
+ list += '
'+name+' | \
+ '+user_list[i]['password']+' | \
+ \
+ 修改 | \
+ 删除 | \
+ 权限 | \
+ 从库同步命令\
+ | \
+
';
+ }
+
+ $('#get_master_rep_slave_list_page tbody').html(list);
+ $('.dataTables_paginate_4').html(rdata['page']);
+ });
+}
+
+function getMasterRepSlaveListPage(){
+ var page = '
';
+ page += '
添加同步账户
';
+
+ var loadOpen = layer.open({
+ type: 1,
+ title: '同步账户列表',
+ area: '500px',
+ content:"
",
+ success:function(){
+ getMasterRepSlaveList();
+ }
+ });
+}
+
+
+function deleteSlave(){
+ myPost('delete_slave', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata['msg'], function(){
+ masterOrSlaveConf();
+ },{},3000);
+ });
+}
+
+
+function getFullSyncStatus(db){
+ var timeId = null;
+
+ var btn = '
开始
';
+ var loadOpen = layer.open({
+ type: 1,
+ title: '全量同步['+db+']',
+ area: '500px',
+ content:"
",
+ cancel: function(){
+ clearInterval(timeId);
+ }
+ });
+
+ function fullSync(db,begin){
+
+ myPostN('full_sync', {db:db,begin:begin}, function(data){
+ var rdata = $.parseJSON(data.data);
+ $('#full_msg').text(rdata['msg']);
+ $('.progress-bar').css('width',rdata['progress']+'%');
+ $('.progress-bar').text(rdata['progress']+'%');
+
+ if (rdata['code']==6 ||rdata['code']<0){
+ layer.msg(rdata['msg']);
+ clearInterval(timeId);
+ $("#begin_full_sync").attr('data-status','init');
+ }
+ });
+ }
+
+ $('#begin_full_sync').click(function(){
+ var val = $(this).attr('data-status');
+ if (val == 'init'){
+ fullSync(db,1);
+ timeId = setInterval(function(){
+ fullSync(db,0);
+ }, 1000);
+ $(this).attr('data-status','starting');
+ } else {
+ layer.msg("正在同步中..");
+ }
+ });
+}
+
+function addSlaveSSH(ip=''){
+
+ myPost('get_slave_ssh_by_ip', {ip:ip}, function(rdata){
+
+ var rdata = $.parseJSON(rdata.data);
+
+ var ip = '127.0.0.1';
+ var port = "22";
+ var id_rsa = '';
+ var db_user ='';
+
+ if (rdata.data.length>0){
+ ip = rdata.data[0]['ip'];
+ port = rdata.data[0]['port'];
+ id_rsa = rdata.data[0]['id_rsa'];
+ db_user = rdata.data[0]['db_user'];
+ }
+
+ var index = layer.open({
+ type: 1,
+ area: ['500px','480px'],
+ title: '添加SSH',
+ closeBtn: 1,
+ shift: 5,
+ shadeClose: true,
+ btn:["确认","取消"],
+ content: "
",
+ success:function(){
+ $('textarea[name="id_rsa"]').html(id_rsa);
+ },
+ yes:function(index){
+ var ip = $('input[name="ip"]').val();
+ var port = $('input[name="port"]').val();
+ var db_user = $('input[name="db_user"]').val();
+ var id_rsa = $('textarea[name="id_rsa"]').val();
+
+ var data = {ip:ip,port:port,id_rsa:id_rsa,db_user:db_user};
+ myPost('add_slave_ssh', data, function(data){
+ layer.close(index);
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ getSlaveSSHPage();
+ }
+ },{icon: rdata.status ? 1 : 2},600);
+ });
+ }
+ });
+ });
+}
+
+
+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();
+ });
+}
+
+function getSlaveSSHPage(page=1){
+ var _data = {};
+ _data['page'] = page;
+ _data['page_size'] = 5;
+ _data['tojs'] ='getSlaveSSHPage';
+ myPost('get_slave_ssh_list', _data, function(data){
+ var layerId = null;
+ var rdata = [];
+ try {
+ rdata = $.parseJSON(data.data);
+ } catch(e) {
+ console.log(e);
+ }
+ var list = '';
+ var ssh_list = rdata['data'];
+ for (i in ssh_list) {
+ var ip = ssh_list[i]['ip'];
+ var port = ssh_list[i]['port'];
+
+ var id_rsa = '未设置';
+ if ( ssh_list[i]['port'] != ''){
+ id_rsa = '已设置';
+ }
+
+ var db_user = '未设置';
+ if ( ssh_list[i]['db_user'] != ''){
+ db_user = ssh_list[i]['db_user'];
+ }
+
+ list += '
'+ip+' | \
+ '+port+' | \
+ '+db_user+' | \
+ '+id_rsa+' | \
+ \
+ 修改 | \
+ 删除\
+ | \
+
';
+ }
+
+ $('.get-slave-ssh-list tbody').html(list);
+ $('.dataTables_paginate_4').html(rdata['page']);
+ });
+}
+
+
+function getSlaveSSHList(page=1){
+
+ var page = '
';
+ page += '
添加SSH
';
+
+ layerId = layer.open({
+ type: 1,
+ title: 'SSH列表',
+ area: '500px',
+ content:"
",
+ success:function(){
+ getSlaveSSHPage(1);
+ }
+ });
+}
+
+function handlerRun(){
+ myPostN('get_slave_sync_cmd', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ var cmd = rdata['data'];
+ var loadOpen = layer.open({
+ type: 1,
+ title: '手动执行',
+ area: '500px',
+ content:"
",
+ });
+ copyPass(cmd);
+ $('.class-copy-cmd').click(function(){
+ copyPass(cmd);
+ });
+ });
+}
+
+function initSlaveStatus(){
+ myPost('init_slave_status', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg,function(){
+ if (rdata.status){
+ masterOrSlaveConf();
+ }
+ },{icon:rdata.status?1:2},2000);
+ });
+}
+
+function masterOrSlaveConf(version=''){
+
+ function getMasterDbList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+
+ myPost('get_masterdb_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+ list += '
';
+ list += '' + rdata.data[i]['name'] +' | ';
+ list += '' + (rdata.data[i]['master']?'是':'否') +' | ';
+ list += '' +
+ ''+(rdata.data[i]['master']?'退出':'加入')+' | ' +
+ '同步命令' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
\
+
\
+
\
+
\
+ 同步账户列表\
+
\
+
';
+
+ $(".table_master_list").html(con);
+ $('#databasePage').html(rdata.page);
+ });
+ }
+
+ function getAsyncMasterDbList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+
+ myPost('get_slave_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+
+ var v = rdata.data[i];
+ var status = "异常";
+ if (v['Slave_SQL_Running'] == 'Yes' && v['Slave_IO_Running'] == 'Yes'){
+ status = "正常";
+ }
+
+ list += '
';
+ list += '' + rdata.data[i]['Master_Host'] +' | ';
+ list += '' + rdata.data[i]['Master_Port'] +' | ';
+ list += '' + rdata.data[i]['Master_User'] +' | ';
+ list += '' + rdata.data[i]['Master_Log_File'] +' | ';
+ list += '' + rdata.data[i]['Slave_IO_Running'] +' | ';
+ list += '' + rdata.data[i]['Slave_SQL_Running'] +' | ';
+ list += '' + status +' | ';
+ list += '' +
+ '删除' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
';
+
+ //
\
+ //
\
+ // 添加\
+ //
+ $(".table_slave_status_list").html(con);
+ });
+ }
+
+ function getAsyncDataList(){
+ var _data = {};
+ if (typeof(page) =='undefined'){
+ var page = 1;
+ }
+
+ _data['page'] = page;
+ _data['page_size'] = 10;
+ myPost('get_masterdb_list', _data, function(data){
+ var rdata = $.parseJSON(data.data);
+ var list = '';
+ for(i in rdata.data){
+ list += '
';
+ list += '' + rdata.data[i]['name'] +' | ';
+ list += '' +
+ ''+(rdata.data[i]['slave']?'退出':'加入')+' | ' +
+ '同步' +
+ ' | ';
+ list += '
';
+ }
+
+ var con = '
\
+
\
+
\
+
\
+ 手动命令\
+ 全量同步\
+
\
+
';
+
+ $(".table_slave_list").html(con);
+ $('#databasePage').html(rdata.page);
+ });
+ }
+
+
+
+ function getMasterStatus(){
+ myPost('get_master_status', '', function(data){
+ var rdata = $.parseJSON(data.data);
+ // console.log('mode:',rdata.data);
+ var rdata = rdata.data;
+ var limitCon = '\
+
\
+ 主从同步模式\
+ \
+ \
+
\
+
\
+
\
+ Master[主]配置\
+ \
+
\
+
\
+ \
+
\
+
\
+ \
+
\
+ Slave[从]配置\
+ \
+ \
+ \
+
\
+
\
+ \
+
\
+ \
+
\
+ ';
+ $(".soft-man-con").html(limitCon);
+
+ //设置主服务器配置
+ $(".btn-master").click(function () {
+ myPost('set_master_status', 'close=change', function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ getMasterStatus();
+ }, 3000);
+ });
+ });
+
+ $(".btn-slave").click(function () {
+ myPost('set_slave_status', 'close=change', function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 5 });
+ setTimeout(function(){
+ getMasterStatus();
+ }, 3000);
+ });
+ });
+
+ $('.db-mode').click(function(){
+ if ($(this).hasClass('btn-success')){
+ //no action
+ return;
+ }
+
+ var mode = 'classic';
+ if ($(this).hasClass('btn-gtid')){
+ mode = 'gtid';
+ }
+
+ layer.open({
+ type:1,
+ title:"MySQL主从模式切换",
+ shadeClose:false,
+ btnAlign: 'c',
+ btn: ['切换并重启', '切换不重启'],
+ yes: function(index, layero){
+ this.change(index,mode,"yes");
+
+ },
+ btn2: function(index, layero){
+ this.change(index,mode,"no");
+ return false;
+ },
+ change:function(index,mode,reload){
+ console.log(index,mode,reload);
+ myPost('set_dbrun_mode',{'mode':mode,'reload':reload},function(data){
+ layer.close(index);
+ var rdata = $.parseJSON(data.data);
+ showMsg(rdata.msg ,function(){
+ getMasterStatus();
+ },{ icon: rdata.status ? 1 : 5 });
+ });
+ }
+ });
+ });
+
+ if (rdata.status){
+ getMasterDbList();
+ }
+
+ if (rdata.slave_status){
+ getAsyncMasterDbList();
+ getAsyncDataList()
+ }
+ });
+ }
+ getMasterStatus();
+}
diff --git a/plugins/postgresql/versions/14.4/install.sh b/plugins/postgresql/versions/14.4/install.sh
new file mode 100755
index 000000000..6dd3a80b8
--- /dev/null
+++ b/plugins/postgresql/versions/14.4/install.sh
@@ -0,0 +1,101 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
+export PATH
+
+#https://www.postgresql.org/ftp/source/
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+sysName=`uname`
+
+install_tmp=${rootPath}/tmp/mw_install.pl
+postgreDir=${serverPath}/source/postgresql
+
+VERSION=14.4
+
+Install_App()
+{
+ mkdir -p ${postgreDir}
+ echo '正在安装脚本文件...' > $install_tmp
+
+ if id postgresql &> /dev/null ;then
+ echo "postgresql UID is `id -u postgresql`"
+ echo "postgresql Shell is `grep "^postgresql:" /etc/passwd |cut -d':' -f7 `"
+ else
+ groupadd postgresql
+ useradd -g postgresql postgresql
+ fi
+
+ if [ "$sysName" != "Darwin" ];then
+ mkdir -p /var/log/mariadb
+ touch /var/log/mariadb/mariadb.log
+ fi
+
+ # ----- cpu start ------
+ if [ -z "${cpuCore}" ]; then
+ cpuCore="1"
+ fi
+
+ if [ -f /proc/cpuinfo ];then
+ cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
+ fi
+
+ MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
+ if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
+ if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
+ cpuCore="${MEM_INFO}"
+ fi
+ else
+ cpuCore="1"
+ fi
+
+ # for stable installation
+ if [ "$cpuCore" -gt "1" ];then
+ cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
+ fi
+ # ----- cpu end ------
+
+ if [ ! -f ${postgreDir}/postgresql-${VERSION}.tar.bz2 ];then
+ wget --no-check-certificate -O ${postgreDir}/postgresql-${VERSION}.tar.bz2 --tries=3 https://ftp.postgresql.org/pub/source/v${VERSION}/postgresql-${VERSION}.tar.bz2
+ fi
+
+ if [ ! -d ${postgreDir}/postgresql-${VERSION} ];then
+ cd ${postgreDir} && tar -jxvf ${postgreDir}/postgresql-${VERSION}.tar.bz2
+ fi
+
+
+ if [ ! -d $serverPath/postgresql ];then
+ cd ${postgreDir}/postgresql-${VERSION} && ./configure \
+ --prefix=$serverPath/postgresql
+ # --with-openssl \
+ # --with-pgport=33206
+
+ echo "cd ${postgreDir}/postgresql-${VERSION} && ./configure \
+ --prefix=$serverPath/postgresql"
+ # --with-openssl \
+ # --with-pgport=33206
+ make -j${cpuCore} && make install && make clean
+ fi
+
+ if [ -d $serverPath/postgresql ];then
+ echo "${VERSION}" > $serverPath/postgresql/version.pl
+ echo 'install successful' > $install_tmp
+ else
+ echo 'install fail' > $install_tmp
+ fi
+}
+
+Uninstall_App()
+{
+ rm -rf $serverPath/postgresql
+ echo '卸载完成' > $install_tmp
+}
+
+action=$1
+if [ "${1}" == "install" ];then
+ Install_App
+else
+ Uninstall_App
+fi
diff --git a/route/static/app/crontab.js b/route/static/app/crontab.js
index 459e65d50..3509bdcf4 100755
--- a/route/static/app/crontab.js
+++ b/route/static/app/crontab.js
@@ -35,7 +35,7 @@ function getLogs(id){
});
setTimeout(function(){
- $("#crontab-log").text(rdata.msg);
+ $("#crontab-log").html(rdata.msg);
},200);
},'json');
}
diff --git a/scripts/backup.py b/scripts/backup.py
index 317f0a10b..12f35bbd6 100755
--- a/scripts/backup.py
+++ b/scripts/backup.py
@@ -112,8 +112,14 @@ class backupTools:
if len(mycnf) > 100:
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
- mw.execShell(
- db_path + "/bin/mysqldump --opt --default-character-set=utf8 " + name + " | gzip > " + filename)
+ # mw.execShell(db_path + "/bin/mysqldump --opt --default-character-set=utf8 " +
+ # name + " | gzip > " + filename)
+
+ # mw.execShell(db_path + "/bin/mysqldump --skip-lock-tables --default-character-set=utf8 " +
+ # name + " | gzip > " + filename)
+
+ mw.execShell(db_path + "/bin/mysqldump --single-transaction --quick --default-character-set=utf8 " +
+ name + " | gzip > " + filename)
if not os.path.exists(filename):
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
@@ -135,7 +141,7 @@ class backupTools:
mw.M('backup').add('type,name,pid,filename,addtime,size', (1, os.path.basename(
filename), pid, filename, endDate, os.path.getsize(filename)))
- log = "数据库[" + name + "]备份成功,用时[" + str(round(outTime, 2)) + u"]秒"
+ log = "数据库[" + name + "]备份成功,用时[" + str(round(outTime, 2)) + "]秒"
mw.writeLog('计划任务', log)
print("★[" + endDate + "] " + log)
print("|---保留最新的[" + count + "]份备份")
diff --git a/scripts/init.d/mw.tpl b/scripts/init.d/mw.tpl
index 1dfbc7984..7d660dc77 100755
--- a/scripts/init.d/mw.tpl
+++ b/scripts/init.d/mw.tpl
@@ -3,7 +3,7 @@
# description: MW Cloud Service
### BEGIN INIT INFO
-# Provides: bt
+# Provides: Midoks
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
diff --git a/scripts/install.sh b/scripts/install.sh
index 91e78049e..e5d11d439 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -58,8 +58,18 @@ if [ $OSNAME != "macos" ];then
mkdir -p /www/backup/database
mkdir -p /www/backup/site
+
+ # https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh
+
if [ ! -d /www/server/mdserver-web ];then
- wget -O /tmp/master.zip https://codeload.github.com/midoks/mdserver-web/zip/master
+
+ cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
+ if [ ! -z "$cn" ];then
+ wget -O /tmp/master.zip https://gitee.com/midoks/mdserver-web/repository/archive/master.zip
+ else
+ wget -O /tmp/master.zip https://codeload.github.com/midoks/mdserver-web/zip/master
+ fi
+
cd /tmp && unzip /tmp/master.zip
mv -f /tmp/mdserver-web-master /www/server/mdserver-web
rm -rf /tmp/master.zip
diff --git a/scripts/lib.sh b/scripts/lib.sh
index 8ed34152b..6c491a156 100755
--- a/scripts/lib.sh
+++ b/scripts/lib.sh
@@ -113,7 +113,7 @@ cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/requirem
pip3 install gevent-websocket==0.10.1
pip3 install flask-caching==1.10.1
-pip3 install mysqlclient
+# pip3 install mysqlclient
if [ ! -f /www/server/mdserver-web/bin/activate ];then
@@ -129,5 +129,5 @@ pip3 install -r /www/server/mdserver-web/requirements.txt
pip3 install gevent-websocket==0.10.1
pip3 install flask-caching==1.10.1
-pip3 install mysqlclient
+# pip3 install mysqlclient
diff --git a/scripts/update.sh b/scripts/update.sh
index dd13727bb..9e6439da2 100755
--- a/scripts/update.sh
+++ b/scripts/update.sh
@@ -46,7 +46,15 @@ else
OSNAME='unknow'
fi
-wget -O /tmp/master.zip https://codeload.github.com/midoks/mdserver-web/zip/master
+
+cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
+if [ ! -z "$cn" ];then
+ wget -O /tmp/master.zip https://gitee.com/midoks/mdserver-web/repository/archive/master.zip
+else
+ wget -O /tmp/master.zip https://codeload.github.com/midoks/mdserver-web/zip/master
+fi
+
+
cd /tmp && unzip /tmp/master.zip
/usr/bin/cp -rf /tmp/mdserver-web-master/* /www/server/mdserver-web
rm -rf /tmp/master.zip