From 60e9f8e143418298faf4eab9714c2a39933e938e Mon Sep 17 00:00:00 2001
From: midoks
Date: Sun, 6 Nov 2022 20:32:02 +0800
Subject: [PATCH 01/10] =?UTF-8?q?=E5=86=8D=E6=AC=A1=E5=8A=A0=E5=85=A5?=
=?UTF-8?q?=E5=88=B0=E6=A0=B8=E5=BF=83=EF=BC=8C=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
plugins/mysql-apt/LICENSE | 201 ++
plugins/mysql-apt/README.md | 5 +
plugins/mysql-apt/class/mysqlDb.py | 99 +
plugins/mysql-apt/conf/my5.7.cnf | 97 +
plugins/mysql-apt/conf/my8.0.cnf | 98 +
plugins/mysql-apt/conf/mysql.sql | 28 +
plugins/mysql-apt/ico.png | Bin 0 -> 1135 bytes
plugins/mysql-apt/index.html | 58 +
plugins/mysql-apt/index.py | 1933 ++++++++++++++++++++
plugins/mysql-apt/info.json | 17 +
plugins/mysql-apt/init.d/mysql.service.tpl | 50 +
plugins/mysql-apt/install.sh | 47 +
plugins/mysql-apt/js/mysql-apt.js | 1735 ++++++++++++++++++
plugins/mysql-apt/scripts/backup.py | 119 ++
plugins/mysql-apt/versions/5.7/install.sh | 118 ++
plugins/mysql-apt/versions/8.0/install.sh | 140 ++
16 files changed, 4745 insertions(+)
create mode 100644 plugins/mysql-apt/LICENSE
create mode 100644 plugins/mysql-apt/README.md
create mode 100755 plugins/mysql-apt/class/mysqlDb.py
create mode 100644 plugins/mysql-apt/conf/my5.7.cnf
create mode 100644 plugins/mysql-apt/conf/my8.0.cnf
create mode 100755 plugins/mysql-apt/conf/mysql.sql
create mode 100644 plugins/mysql-apt/ico.png
create mode 100755 plugins/mysql-apt/index.html
create mode 100755 plugins/mysql-apt/index.py
create mode 100755 plugins/mysql-apt/info.json
create mode 100644 plugins/mysql-apt/init.d/mysql.service.tpl
create mode 100755 plugins/mysql-apt/install.sh
create mode 100755 plugins/mysql-apt/js/mysql-apt.js
create mode 100755 plugins/mysql-apt/scripts/backup.py
create mode 100755 plugins/mysql-apt/versions/5.7/install.sh
create mode 100755 plugins/mysql-apt/versions/8.0/install.sh
diff --git a/plugins/mysql-apt/LICENSE b/plugins/mysql-apt/LICENSE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/plugins/mysql-apt/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/plugins/mysql-apt/README.md b/plugins/mysql-apt/README.md
new file mode 100644
index 000000000..166c7c2d5
--- /dev/null
+++ b/plugins/mysql-apt/README.md
@@ -0,0 +1,5 @@
+# mysql-apt
+mysql 在ubuntu,debian的apt安装方式
+
+
+无法使用
\ No newline at end of file
diff --git a/plugins/mysql-apt/class/mysqlDb.py b/plugins/mysql-apt/class/mysqlDb.py
new file mode 100755
index 000000000..6f5d74ecc
--- /dev/null
+++ b/plugins/mysql-apt/class/mysqlDb.py
@@ -0,0 +1,99 @@
+# coding: utf-8
+
+import re
+import os
+import sys
+
+# sys.path.append("/usr/local/lib/python3.9/site-packages")
+
+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)
+
+
+class mysqlDb:
+ __DB_PASS = None
+ __DB_USER = 'root'
+ __DB_PORT = 3306
+ __DB_HOST = 'localhost'
+ __DB_CONN = None
+ __DB_CUR = None
+ __DB_ERR = None
+ __DB_CNF = '/etc/my.cnf'
+
+ def __Conn(self):
+ '''连接MYSQL数据库'''
+ try:
+ import mw
+ socket = '/www/server/mysql-ya/mysql.sock'
+ try:
+ import MySQLdb
+ except Exception as ex:
+ # print('dd')
+ self.__DB_ERR = ex
+ return False
+ try:
+ myconf = mw.readFile(self.__DB_CNF)
+ rep = "port\s*=\s*([0-9]+)"
+ self.__DB_PORT = int(re.search(rep, myconf).groups()[0])
+ except:
+ self.__DB_PORT = 3306
+ # print self.__DB_PASS
+ #self.__DB_PASS = mw.M('config').where('id=?', (1,)).getField('mysql_root')
+ try:
+ self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=socket)
+ except MySQLdb.Error as e:
+ self.__DB_HOST = '127.0.0.1'
+ self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
+ port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=socket)
+ self.__DB_CUR = self.__DB_CONN.cursor()
+ return True
+ except MySQLdb.Error as e:
+ self.__DB_ERR = e
+ return False
+
+ def setDbConf(self, conf):
+ self.__DB_CNF = conf
+
+ def setPwd(self, pwd):
+ self.__DB_PASS = pwd
+
+ def getPwd(self):
+ return self.__DB_PASS
+
+ def execute(self, sql):
+ # 执行SQL语句返回受影响行
+ if not self.__Conn():
+ return self.__DB_ERR
+ try:
+ result = self.__DB_CUR.execute(sql)
+ self.__DB_CONN.commit()
+ self.__Close()
+ return result
+ except Exception as ex:
+ return ex
+
+ def query(self, sql):
+ # 执行SQL语句返回数据集
+ if not self.__Conn():
+ return self.__DB_ERR
+ try:
+ self.__DB_CUR.execute(sql)
+ result = self.__DB_CUR.fetchall()
+ # 将元组转换成列表
+ # data = list(map(list, result))
+ self.__Close()
+ return result
+ except Exception as ex:
+ return ex
+
+ # 关闭连接
+ def __Close(self):
+ self.__DB_CUR.close()
+ self.__DB_CONN.close()
diff --git a/plugins/mysql-apt/conf/my5.7.cnf b/plugins/mysql-apt/conf/my5.7.cnf
new file mode 100644
index 000000000..847bc276e
--- /dev/null
+++ b/plugins/mysql-apt/conf/my5.7.cnf
@@ -0,0 +1,97 @@
+[client]
+user = root
+#password = your_password
+port = 3376
+socket = {$SERVER_APP_PATH}/mysql.sock
+default-character-set = UTF8MB4
+
+[mysqld]
+pid-file = {$SERVER_APP_PATH}/data/mysql.pid
+user = mysql
+port = 3376
+mysqlx_port = 33760
+socket = {$SERVER_APP_PATH}/mysql.sock
+datadir = {$SERVER_APP_PATH}/data
+log-error = {$SERVER_APP_PATH}/data/error.log
+default_storage_engine = MyISAM
+
+key_buffer_size = 8M
+table_open_cache = 32
+sort_buffer_size = 256K
+net_buffer_length = 4K
+read_buffer_size = 128K
+read_rnd_buffer_size = 256K
+myisam_sort_buffer_size = 4M
+thread_cache_size = 4
+lower_case_table_names=0
+tmp_table_size = 8M
+character-set-server = UTF8MB4
+
+max_connections = 500
+max_connect_errors = 100
+open_files_limit = 2560
+max_allowed_packet = 128M
+
+#skip-external-locking
+#skip-grant-tables
+#loose-skip-innodb
+#skip-networking
+#skip-name-resolve
+
+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
+
+relay-log=mdserver
+relay-log-index=mdserver
+
+#master
+#binlog-do-db
+binlog-ignore-db = test
+binlog-ignore-db = mysql
+binlog-ignore-db = information_schema
+binlog-ignore-db = performance_schema
+
+#slave
+log-slave-updates
+#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_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
+
+[mysqldump]
+quick
+
+[mysql]
+no-auto-rehash
+
+[myisamchk]
+key_buffer_size = 20M
+sort_buffer_size = 20M
+read_buffer = 2M
+write_buffer = 2M
+
+[mysqlhotcopy]
+interactive-timeout
\ No newline at end of file
diff --git a/plugins/mysql-apt/conf/my8.0.cnf b/plugins/mysql-apt/conf/my8.0.cnf
new file mode 100644
index 000000000..934657c4b
--- /dev/null
+++ b/plugins/mysql-apt/conf/my8.0.cnf
@@ -0,0 +1,98 @@
+[client]
+user = root
+#password = your_password
+port = 3386
+socket = {$SERVER_APP_PATH}/mysql.sock
+default-character-set = UTF8MB4
+
+[mysqld]
+default_authentication_plugin=mysql_native_password
+pid-file = {$SERVER_APP_PATH}/data/mysql.pid
+user = mysql
+port = 3386
+mysqlx_port = 33860
+socket = {$SERVER_APP_PATH}/mysql.sock
+datadir = {$SERVER_APP_PATH}/data
+log-error = {$SERVER_APP_PATH}/data/error.log
+default_storage_engine = MyISAM
+
+key_buffer_size = 8M
+table_open_cache = 32
+sort_buffer_size = 256K
+net_buffer_length = 4K
+read_buffer_size = 128K
+read_rnd_buffer_size = 256K
+myisam_sort_buffer_size = 4M
+thread_cache_size = 4
+lower_case_table_names=0
+tmp_table_size = 8M
+character-set-server = UTF8MB4
+
+max_connections = 500
+max_connect_errors = 100
+open_files_limit = 2560
+max_allowed_packet = 128M
+
+#skip-external-locking
+#skip-grant-tables
+#loose-skip-innodb
+#skip-networking
+#skip-name-resolve
+
+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
+
+relay-log=mdserver
+relay-log-index=mdserver
+
+#master
+#binlog-do-db
+binlog-ignore-db = test
+binlog-ignore-db = mysql
+binlog-ignore-db = information_schema
+binlog-ignore-db = performance_schema
+
+#slave
+log_replica_updates
+#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_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
+
+[mysqldump]
+quick
+
+[mysql]
+no-auto-rehash
+
+[myisamchk]
+key_buffer_size = 20M
+sort_buffer_size = 20M
+read_buffer = 2M
+write_buffer = 2M
+
+[mysqlhotcopy]
+interactive-timeout
\ No newline at end of file
diff --git a/plugins/mysql-apt/conf/mysql.sql b/plugins/mysql-apt/conf/mysql.sql
new file mode 100755
index 000000000..38b822738
--- /dev/null
+++ b/plugins/mysql-apt/conf/mysql.sql
@@ -0,0 +1,28 @@
+CREATE TABLE IF NOT EXISTS `config` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `mysql_root` TEXT
+);
+
+INSERT INTO `config` (`id`, `mysql_root`) VALUES (1, 'admin');
+
+CREATE TABLE IF NOT EXISTS `databases` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `pid` INTEGER,
+ `name` TEXT,
+ `username` TEXT,
+ `password` TEXT,
+ `accept` TEXT,
+ `ps` TEXT,
+ `addtime` TEXT
+);
+
+CREATE TABLE IF NOT EXISTS `master_replication_user` (
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
+ `username` TEXT,
+ `password` TEXT,
+ `accept` TEXT,
+ `ps` TEXT,
+ `addtime` TEXT
+);
+
+
diff --git a/plugins/mysql-apt/ico.png b/plugins/mysql-apt/ico.png
new file mode 100644
index 0000000000000000000000000000000000000000..ead815fc20cc747780967ef2871b83c000e4f82d
GIT binary patch
literal 1135
zcmV-#1d#iQP)>{3lQ%rYE>EIo|Bc9O8-^_)1agG}q9>-P216(B
zK}1dolB(O#w(T^gZ+;f7TTURgp@*LLi%EvgY=cZDhv*1Q%s|VgV~ETx1Bb!tAi=x$
zUWdVBccSOOP0TAdp?2kNQqbh`6_+AM=z=O#FWZiQgf#GjdIS}L4KI9;
zf}sTnN>=9>ibj?}Z*{;EbY?5sx1YxBZ7&Kol9MINSyjpHnF1j5xR->al|lgp3yToqeV
zi#1Puj`)fuTy=C78)}wr|E;r9Us(3QJIL;u;2qai|6mNCx)=S2ZoTRgD-Cf~i(61M
zx(o`X3N_1iVCx${VeI@Pv@i2P$%IaC9>B`SKIRNTVJVXE
z2#%m|zDZ4GHL+7*QfNoPf=^*t~;eZXN43`ND
z7cv<&LC*S9H$H{xrQ7Jlg9?E+DPi*uMqb|xC2+^ia|lk(@-ihrD=Xzh`OJFMEZYt$
z$xJyfgDMjpD9034i#I2DjNYWkmE7JWBqSsxeg^A1@>H
+
+
+
+
+
服务
+
自启动
+
配置文件
+
存储位置
+
端口
+
当前状态
+
性能优化
+
日志
+
错误日志
+
慢日志
+
管理列表
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/mysql-apt/index.py b/plugins/mysql-apt/index.py
new file mode 100755
index 000000000..2319faef3
--- /dev/null
+++ b/plugins/mysql-apt/index.py
@@ -0,0 +1,1933 @@
+# 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 'mysql-apt'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+sys.path.append(getPluginDir() + "/class")
+import mysqlDb
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+def is_number(s):
+ try:
+ float(s)
+ return True
+ except ValueError:
+ pass
+
+ try:
+ import unicodedata
+ unicodedata.numeric(s)
+ return True
+ except (TypeError, ValueError):
+ pass
+
+ return False
+
+
+def getArgs():
+ args = sys.argv[2:]
+
+ 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() + '/etc/my.cnf'
+ 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('{$SERVER_APP_PATH}',
+ service_path + '/' + getPluginName())
+ return content
+
+
+def pSqliteDb(dbname='databases'):
+ file = getServerDir() + '/mysql.db'
+ name = 'mysql'
+ if not os.path.exists(file):
+ 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], ())
+ 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():
+ db = mysqlDb.mysqlDb()
+ db.__DB_CNF = getConf()
+ db.setDbConf(getConf())
+ db.setPwd(pSqliteDb('config').where(
+ 'id=?', (1,)).getField('mysql_root'))
+ return db
+
+
+def initDreplace(version=''):
+
+ mysql_conf_dir = getServerDir() + '/etc'
+ if not os.path.exists(mysql_conf_dir):
+ os.mkdir(mysql_conf_dir)
+
+ mysql_tmp = getServerDir() + '/tmp'
+ if not os.path.exists(mysql_tmp):
+ os.mkdir(mysql_tmp)
+ mw.execShell("chown -R mysql:mysql " + mysql_tmp)
+
+ mysql_conf = mysql_conf_dir + '/my.cnf'
+ if not os.path.exists(mysql_conf):
+ mysql_conf_tpl = getPluginDir() + '/conf/my' + version + '.cnf'
+ content = mw.readFile(mysql_conf_tpl)
+ content = contentReplace(content)
+ mw.writeFile(mysql_conf, content)
+
+ # systemd
+ systemDir = mw.systemdCfgDir()
+ systemService = systemDir + '/mysql-apt.service'
+ systemServiceTpl = getPluginDir() + '/init.d/mysql.service.tpl'
+ if os.path.exists(systemDir) and not os.path.exists(systemService):
+ service_path = mw.getServerDir()
+ se_content = mw.readFile(systemServiceTpl)
+ se_content = se_content.replace('{$SERVER_PATH}', service_path)
+ mw.writeFile(systemService, se_content)
+ mw.execShell('systemctl daemon-reload')
+
+ if mw.getOs() != 'darwin':
+ mw.execShell('chown -R mysql mysql ' + getServerDir())
+ return 'ok'
+
+
+def status(version=''):
+ pid = getPidFile()
+ if not os.path.exists(pid):
+ 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 binLog():
+ args = getArgs()
+ conf = getConf()
+ con = mw.readFile(conf)
+
+ if con.find('#log-bin=mysql-bin') != -1:
+ if 'status' in args:
+ return mw.returnJson(False, '0')
+ con = con.replace('#log-bin=mysql-bin', 'log-bin=mysql-bin')
+ con = con.replace('#binlog_format=mixed', 'binlog_format=mixed')
+ mw.execShell('sync')
+ restart()
+ else:
+ path = getDataDir()
+ if 'status' in args:
+ dsize = 0
+ for n in os.listdir(path):
+ if len(n) < 9:
+ continue
+ if n[0:9] == 'mysql-bin':
+ dsize += os.path.getsize(path + '/' + n)
+ return mw.returnJson(True, dsize)
+ con = con.replace('log-bin=mysql-bin', '#log-bin=mysql-bin')
+ con = con.replace('binlog_format=mixed', '#binlog_format=mixed')
+ mw.execShell('sync')
+ restart()
+ mw.execShell('rm -f ' + path + '/mysql-bin.*')
+
+ mw.writeFile(conf, con)
+ return mw.returnJson(True, '设置成功!')
+
+
+def setSkipGrantTables(v):
+ '''
+ 设置是否密码验证
+ '''
+ conf = getConf()
+ con = mw.readFile(conf)
+ if v:
+ if con.find('#skip-grant-tables') != -1:
+ con = con.replace('#skip-grant-tables', 'skip-grant-tables')
+ else:
+ con = con.replace('skip-grant-tables', '#skip-grant-tables')
+ mw.writeFile(conf, con)
+ return True
+
+
+def getErrorLog():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'log-error\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+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 'mysql'
+
+
+def initMysql57Data():
+ datadir = getDataDir()
+ if not os.path.exists(datadir + '/mysql'):
+ serverdir = getServerDir()
+ myconf = serverdir + "/etc/my.cnf"
+ user = pGetDbUser()
+
+ cmd = 'mysqld --defaults-file=' + myconf + \
+ ' --initialize-insecure --explicit_defaults_for_timestamp'
+ mw.execShell(cmd)
+ return False
+ return True
+
+
+def initMysql8Data():
+ '''
+ chmod 644 /www/server/mysql-apt/etc/my.cnf
+ try:
+ mysqld --basedir=/usr --datadir=/www/server/mysql-apt/data --initialize-insecure
+ mysqld --defaults-file=/www/server/mysql-apt/etc/my.cnf --initialize-insecure
+ mysqld --initialize-insecure
+ select user, plugin from user;
+ update user set authentication_string=password("123123"),plugin='mysql_native_password' where user='root';
+ '''
+ datadir = getDataDir()
+ if not os.path.exists(datadir + '/mysql'):
+ serverdir = getServerDir()
+ user = pGetDbUser()
+
+ cmd = 'mysqld --basedir=/usr --datadir=' + datadir + ' --initialize-insecure'
+ data = mw.execShell(cmd)
+ if data[1].find('ERROR') != -1:
+ exit("Init MySQL{} Data Error".format(8))
+
+ mw.execShell('chown -R mysql mysql ' + getServerDir())
+ return False
+ return True
+
+
+def initMysql8Pwd():
+ time.sleep(5)
+ pwd = mw.getRandomString(16)
+
+ alter_root_pwd = 'flush privileges;'
+ alter_root_pwd = alter_root_pwd + \
+ "alter user 'root'@'localhost' IDENTIFIED by '" + pwd + "';"
+ alter_root_pwd = alter_root_pwd + \
+ "alter user 'root'@'localhost' IDENTIFIED WITH mysql_native_password by '" + pwd + "';"
+ alter_root_pwd = alter_root_pwd + "flush privileges;"
+
+ cmd_pass = 'mysqladmin --defaults-file=' + \
+ getServerDir() + '/etc/my.cnf -uroot password root'
+ data = mw.execShell(cmd_pass)
+ # print(data)
+
+ tmp_file = "/tmp/mysql_ya_init_tmp.log"
+ mw.writeFile(tmp_file, alter_root_pwd)
+ cmd_pass = 'mysql --defaults-file=' + \
+ getServerDir() + '/etc/my.cnf -uroot -proot < ' + tmp_file
+
+ data = mw.execShell(cmd_pass)
+ # print(data)
+ os.remove(tmp_file)
+
+ pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
+
+ return True
+
+
+def my8cmd(version, method):
+ initDreplace(version)
+ # mysql 8.0 and 5.7
+ try:
+ if version == '5.7':
+ isInited = initMysql57Data()
+ elif version == '8.0':
+ isInited = initMysql8Data()
+
+ if not isInited:
+ mw.execShell('systemctl start ' + getPluginName())
+ initMysql8Pwd()
+ mw.execShell('systemctl stop ' + getPluginName())
+
+ mw.execShell('systemctl ' + method + ' ' + getPluginName())
+ return 'ok'
+ except Exception as e:
+ return str(e)
+
+
+def appCMD(version, action):
+ return my8cmd(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 ' + \
+ getPluginName() + ' | 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 ' + getPluginName())
+ return 'ok'
+
+
+def initdUinstall():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+
+ mw.execShell('systemctl disable ' + getPluginName())
+ 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 getMyPort():
+ file = getConf()
+ content = mw.readFile(file)
+ rep = 'port\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ return tmp.groups()[0].strip()
+
+
+def setMyPort():
+ 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, 'MySQL未启动', [])
+
+ 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']
+
+ try:
+ # print data
+ if data[0] == 1045 or data[0] == 2003:
+ pwd = db.getPwd()
+ return mw.returnJson(False, 'mysql password error:' + pwd + '!')
+ except Exception as e:
+ return mw.returnJson(False, str(e))
+
+ result = {}
+ # print(data)
+ for d in data:
+ for g in gets:
+ if d[0] == g:
+ result[g] = d[1]
+
+ # print(result, int(result['Uptime']))
+ 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]
+ except:
+ result['File'] = 'OFF'
+ result['Position'] = 'OFF'
+ return mw.getJson(result)
+
+
+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:
+ for g in gets:
+ if d[0] == g:
+ result['mem'][g] = d[1]
+ # if result['mem']['query_cache_type'] != 'ON':
+ # result['mem']['query_cache_size'] = '0'
+ 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 isSqlError(mysqlMsg):
+ # 检测数据库执行错误
+ mysqlMsg = str(mysqlMsg)
+ if "MySQLdb" in mysqlMsg:
+ return mw.returnJson(False, 'MySQLdb组件缺失! 进入SSH命令行输入: pip install mysql-python | pip install mysqlclient==2.0.3')
+ if "2002," in mysqlMsg:
+ return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
+ if "2003," in mysqlMsg:
+ return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
+ if "using password:" in mysqlMsg:
+ return mw.returnJson(False, '数据库管理密码错误!')
+ if "Connection refused" in mysqlMsg:
+ return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
+ if "1133" in mysqlMsg:
+ return mw.returnJson(False, '数据库用户不存在!')
+ if "1007" in mysqlMsg:
+ return mw.returnJson(False, '数据库已经存在!')
+ if "1045" in mysqlMsg:
+ return mw.returnJson(False, '数据库管理密码错误!')
+ 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()
+
+ 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,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 syncGetDatabases():
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+ data = pdb.query('show databases')
+ isError = isSqlError(data)
+ if isError != None:
+ return isError
+ users = pdb.query(
+ "select User,Host from mysql.user where User!='root' AND Host!='localhost' AND Host!=''")
+ nameArr = ['information_schema', 'performance_schema', 'mysql', 'sys']
+ n = 0
+ for value in data:
+ b = False
+ for key in nameArr:
+ if value[0] == key:
+ b = True
+ break
+ if b:
+ continue
+ if psdb.where("name=?", (value[0],)).count():
+ continue
+ host = '127.0.0.1'
+ for user in users:
+ if value[0] == user[0]:
+ host = user[1]
+ break
+
+ ps = mw.getMsg('INPUT_PS')
+ if value[0] == 'test':
+ ps = mw.getMsg('DATABASE_TEST')
+ addTime = time.strftime('%Y-%m-%d %X', time.localtime())
+ if psdb.add('name,username,password,accept,ps,addtime', (value[0], value[0], '', host, ps, addTime)):
+ n += 1
+
+ msg = mw.getInfo('本次共从服务器获取了{1}个数据库!', (str(n),))
+ return mw.returnJson(True, msg)
+
+
+def toDbBase(find):
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+ if len(find['password']) < 3:
+ find['username'] = find['name']
+ find['password'] = mw.md5(str(time.time()) + find['name'])[0:10]
+ psdb.where("id=?", (find['id'],)).save(
+ 'password,username', (find['password'], find['username']))
+
+ result = pdb.execute("create database `" + find['name'] + "`")
+ if "using password:" in str(result):
+ return -1
+ if "Connection refused" in str(result):
+ return -1
+
+ password = find['password']
+ __createUser(find['name'], find['username'], password, find['accept'])
+ return 1
+
+
+def syncToDatabases():
+ args = getArgs()
+ data = checkArgs(args, ['type', 'ids'])
+ if not data[0]:
+ return data[1]
+
+ pdb = pMysqlDb()
+ result = pdb.execute("show databases")
+ isError = isSqlError(result)
+ if isError:
+ return isError
+
+ stype = int(args['type'])
+ psdb = pSqliteDb('databases')
+ n = 0
+
+ if stype == 0:
+ data = psdb.field('id,name,username,password,accept').select()
+ for value in data:
+ result = toDbBase(value)
+ if result == 1:
+ n += 1
+ else:
+ data = json.loads(args['ids'])
+ for value in data:
+ find = psdb.where("id=?", (value,)).field(
+ 'id,name,username,password,accept').find()
+ # print find
+ result = toDbBase(find)
+ if result == 1:
+ n += 1
+ msg = mw.getInfo('本次共同步了{1}个数据库!', (str(n),))
+ return mw.returnJson(True, msg)
+
+
+def setRootPwd():
+ args = getArgs()
+ data = checkArgs(args, ['password'])
+ if not data[0]:
+ return data[1]
+
+ password = args['password']
+ try:
+ pdb = pMysqlDb()
+ result = pdb.query("show databases")
+ isError = isSqlError(result)
+ 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'")
+ pdb.execute("flush privileges")
+ pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
+ return mw.returnJson(True, '数据库root密码修改成功!')
+ except Exception as ex:
+ return mw.returnJson(False, '修改错误:' + str(ex))
+
+
+def setUserPwd():
+ args = getArgs()
+ data = checkArgs(args, ['password', 'name'])
+ if not data[0]:
+ return data[1]
+
+ newpassword = args['password']
+ username = args['name']
+ id = args['id']
+ try:
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+ name = psdb.where('id=?', (id,)).getField('name')
+
+ m_version = mw.readFile(getServerDir() + '/version.pl')
+ if m_version.find('5.7') == 0 or m_version.find('8.0') == 0:
+ tmp = pdb.query(
+ "select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
+ accept = mapToList(tmp)
+ 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[0], newpassword))
+ else:
+ result = pdb.execute("update mysql.user set Password=password('" +
+ newpassword + "') where User='" + username + "'")
+ isError = isSqlError(result)
+ if isError != None:
+ return isError
+ pdb.execute("flush privileges")
+ psdb.where("id=?", (id,)).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,)))
+
+
+def setDbPs():
+ args = getArgs()
+ data = checkArgs(args, ['id', 'name', 'ps'])
+ if not data[0]:
+ return data[1]
+
+ ps = args['ps']
+ sid = args['id']
+ name = args['name']
+ try:
+ psdb = pSqliteDb('databases')
+ psdb.where("id=?", (sid,)).setField('ps', ps)
+ return mw.returnJson(True, mw.getInfo('修改数据库[{1}]备注成功!', (name,)))
+ except Exception as e:
+ return mw.returnJson(True, mw.getInfo('修改数据库[{1}]备注失败!', (name,)))
+
+
+def addDb():
+ args = getArgs()
+ data = checkArgs(args,
+ ['password', 'name', 'codeing', 'db_user', 'dataAccess', 'ps'])
+ if not data[0]:
+ return data[1]
+
+ if not 'address' in args:
+ address = ''
+ else:
+ address = args['address'].strip()
+
+ dbname = args['name'].strip()
+ dbuser = args['db_user'].strip()
+ codeing = args['codeing'].strip()
+ password = args['password'].strip()
+ dataAccess = args['dataAccess'].strip()
+ ps = args['ps'].strip()
+
+ reg = "^[\w\.-]+$"
+ if not re.match(reg, args['name']):
+ return mw.returnJson(False, '数据库名称不能带有特殊符号!')
+ checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
+ if dbuser in checks or len(dbuser) < 1:
+ return mw.returnJson(False, '数据库用户名不合法!')
+ if dbname in checks or len(dbname) < 1:
+ return mw.returnJson(False, '数据库名称不合法!')
+
+ if len(password) < 1:
+ password = mw.md5(time.time())[0:8]
+
+ wheres = {
+ 'utf8': 'utf8_general_ci',
+ 'utf8mb4': 'utf8mb4_general_ci',
+ 'gbk': 'gbk_chinese_ci',
+ 'big5': 'big5_chinese_ci'
+ }
+ codeStr = wheres[codeing]
+
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+
+ if psdb.where("name=? or username=?", (dbname, dbuser)).count():
+ return mw.returnJson(False, '数据库已存在!')
+
+ result = pdb.execute("create database `" + dbname +
+ "` DEFAULT CHARACTER SET " + codeing + " COLLATE " + codeStr)
+ # print result
+ isError = isSqlError(result)
+ if isError != None:
+ return isError
+
+ pdb.execute("drop user '" + dbuser + "'@'localhost'")
+ for a in address.split(','):
+ pdb.execute("drop user '" + dbuser + "'@'" + a + "'")
+
+ __createUser(dbname, dbuser, password, address)
+
+ addTime = time.strftime('%Y-%m-%d %X', time.localtime())
+ psdb.add('pid,name,username,password,accept,ps,addtime',
+ (0, dbname, dbuser, password, address, ps, addTime))
+ return mw.returnJson(True, '添加成功!')
+
+
+def delDb():
+ args = getArgs()
+ data = checkArgs(args, ['id', 'name'])
+ if not data[0]:
+ return data[1]
+ try:
+ id = args['id']
+ name = args['name']
+ psdb = pSqliteDb('databases')
+ pdb = pMysqlDb()
+ find = psdb.where("id=?", (id,)).field(
+ 'id,pid,name,username,password,accept,ps,addtime').find()
+ accept = find['accept']
+ username = find['username']
+
+ # 删除MYSQL
+ result = pdb.execute("drop database `" + name + "`")
+ isError = isSqlError(result)
+ if isError != None:
+ return isError
+
+ users = pdb.query(
+ "select Host from mysql.user where User='" + username + "' AND Host!='localhost'")
+ pdb.execute("drop user '" + username + "'@'localhost'")
+ for us in users:
+ pdb.execute("drop user '" + username + "'@'" + us[0] + "'")
+ pdb.execute("flush privileges")
+
+ # 删除SQLITE
+ psdb.where("id=?", (id,)).delete()
+ return mw.returnJson(True, '删除成功!')
+ except Exception as ex:
+ return mw.returnJson(False, '删除失败!' + str(ex))
+
+
+def getDbAccess():
+ args = getArgs()
+ data = checkArgs(args, ['username'])
+ if not data[0]:
+ return data[1]
+ username = args['username']
+ pdb = pMysqlDb()
+
+ users = pdb.query("select Host from mysql.user where User='" +
+ username + "' AND Host!='localhost'")
+ isError = isSqlError(users)
+ if isError != None:
+ return isError
+
+ users = mapToList(users)
+ if len(users) < 1:
+ return mw.returnJson(True, "127.0.0.1")
+ accs = []
+ for c in users:
+ accs.append(c[0])
+ userStr = ','.join(accs)
+ 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'])
+ if not data[0]:
+ return data[1]
+ name = args['username']
+ access = args['access']
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('databases')
+
+ dbname = psdb.where('username=?', (name,)).getField('name')
+
+ if name == 'root':
+ password = pSqliteDb('config').where(
+ 'id=?', (1,)).getField('mysql_root')
+ else:
+ password = psdb.where("username=?", (name,)).getField('password')
+ users = pdb.query("select Host from mysql.user where User='" +
+ name + "' AND Host!='localhost'")
+ for us in users:
+ pdb.execute("drop user '" + name + "'@'" + us[0] + "'")
+
+ __createUser(dbname, name, password, access)
+
+ psdb.where('username=?', (name,)).save('accept', (access,))
+ return mw.returnJson(True, '设置成功!')
+
+
+def getDbInfo():
+ args = getArgs()
+ data = checkArgs(args, ['name'])
+ if not data[0]:
+ return data[1]
+
+ db_name = args['name']
+ pdb = pMysqlDb()
+ # print 'show tables from `%s`' % db_name
+ table_res = pdb.query('show tables from `%s`' % db_name)
+ isError = isSqlError(table_res)
+ if isError != None:
+ return isError
+
+ tables = mapToList(table_res)
+
+ ret = {}
+ if type(tables) == list:
+ try:
+ data = mapToList(pdb.query(
+ "select sum(DATA_LENGTH)+sum(INDEX_LENGTH) from information_schema.tables where table_schema='%s'" % db_name))[0][0]
+ except:
+ data = 0
+
+ if not data:
+ data = 0
+ ret['data_size'] = mw.toSize(data)
+ # print ret
+ ret['database'] = db_name
+
+ ret3 = []
+
+ for i in tables:
+ if i == 1049:
+ return mw.returnJson(False, '指定数据库不存在!')
+ table = mapToList(
+ pdb.query("show table status from `%s` where name = '%s'" % (db_name, i[0])))
+ if not table:
+ continue
+ try:
+ ret2 = {}
+ ret2['type'] = table[0][1]
+ ret2['rows_count'] = table[0][4]
+ ret2['collation'] = table[0][14]
+ data_size = table[0][6] + table[0][8]
+ ret2['data_byte'] = data_size
+ ret2['data_size'] = mw.toSize(data_size)
+ ret2['table_name'] = i[0]
+ ret3.append(ret2)
+ except:
+ continue
+ ret['tables'] = (ret3)
+
+ return mw.getJson(ret)
+
+
+def repairTable():
+ args = getArgs()
+ data = checkArgs(args, ['db_name', 'tables'])
+ if not data[0]:
+ return data[1]
+
+ db_name = args['db_name']
+ tables = json.loads(args['tables'])
+ pdb = pMysqlDb()
+ mysql_table = mapToList(pdb.query('show tables from `%s`' % db_name))
+ ret = []
+ if type(mysql_table) == list:
+ if len(mysql_table) > 0:
+ for i in mysql_table:
+ for i2 in tables:
+ if i2 == i[0]:
+ ret.append(i2)
+ if len(ret) > 0:
+ for i in ret:
+ pdb.execute('REPAIR TABLE `%s`.`%s`' % (db_name, i))
+ return mw.returnJson(True, "修复完成!")
+ return mw.returnJson(False, "修复失败!")
+
+
+def optTable():
+ args = getArgs()
+ data = checkArgs(args, ['db_name', 'tables'])
+ if not data[0]:
+ return data[1]
+
+ db_name = args['db_name']
+ tables = json.loads(args['tables'])
+ pdb = pMysqlDb()
+ mysql_table = mapToList(pdb.query('show tables from `%s`' % db_name))
+ ret = []
+ if type(mysql_table) == list:
+ if len(mysql_table) > 0:
+ for i in mysql_table:
+ for i2 in tables:
+ if i2 == i[0]:
+ ret.append(i2)
+ if len(ret) > 0:
+ for i in ret:
+ pdb.execute('OPTIMIZE TABLE `%s`.`%s`' % (db_name, i))
+ return mw.returnJson(True, "优化成功!")
+ return mw.returnJson(False, "优化失败或者已经优化过了!")
+
+
+def alterTable():
+ args = getArgs()
+ data = checkArgs(args, ['db_name', 'tables'])
+ if not data[0]:
+ return data[1]
+
+ db_name = args['db_name']
+ tables = json.loads(args['tables'])
+ table_type = args['table_type']
+ pdb = pMysqlDb()
+ mysql_table = mapToList(pdb.query('show tables from `%s`' % db_name))
+ ret = []
+ if type(mysql_table) == list:
+ if len(mysql_table) > 0:
+ for i in mysql_table:
+ for i2 in tables:
+ if i2 == i[0]:
+ ret.append(i2)
+ if len(ret) > 0:
+ for i in ret:
+ pdb.execute('alter table `%s`.`%s` ENGINE=`%s`' %
+ (db_name, i, table_type))
+ return mw.returnJson(True, "更改成功!")
+ return mw.returnJson(False, "更改失败!")
+
+
+def getTotalStatistics():
+ st = status()
+ data = {}
+
+ isInstall = os.path.exists(getServerDir() + '/version.pl')
+
+ if st == 'start' and isInstall:
+ data['status'] = True
+ data['count'] = pSqliteDb('databases').count()
+ data['ver'] = mw.readFile(getServerDir() + '/version.pl').strip()
+ return mw.returnJson(True, 'ok', data)
+ else:
+ data['status'] = False
+ data['count'] = 0
+ return mw.returnJson(False, 'fail', data)
+
+
+def findBinlogDoDb():
+ conf = getConf()
+ con = mw.readFile(conf)
+ rep = r"binlog-do-db\s*?=\s*?(.*)"
+ dodb = re.findall(rep, con, re.M)
+ return dodb
+
+
+def findBinlogSlaveDoDb():
+ conf = getConf()
+ con = mw.readFile(conf)
+ rep = r"replicate-do-db\s*?=\s*?(.*)"
+ dodb = re.findall(rep, con, re.M)
+ return dodb
+
+
+def getMasterDbList(version=''):
+ args = getArgs()
+ page = 1
+ page_size = 10
+ search = ''
+ data = {}
+ if 'page' in args:
+ page = int(args['page'])
+
+ if 'page_size' in args:
+ page_size = int(args['page_size'])
+
+ if 'search' in args:
+ search = args['search']
+
+ conn = pSqliteDb('databases')
+ limit = str((page - 1) * page_size) + ',' + str(page_size)
+ condition = ''
+ dodb = findBinlogDoDb()
+ data['dodb'] = dodb
+
+ slave_dodb = findBinlogSlaveDoDb()
+
+ if not search == '':
+ condition = "name like '%" + search + "%'"
+ field = 'id,pid,name,username,password,accept,ps,addtime'
+ clist = conn.where(condition, ()).field(
+ field).limit(limit).order('id desc').select()
+ count = conn.where(condition, ()).count()
+
+ for x in range(0, len(clist)):
+ if clist[x]['name'] in dodb:
+ clist[x]['master'] = 1
+ else:
+ clist[x]['master'] = 0
+
+ if clist[x]['name'] in slave_dodb:
+ clist[x]['slave'] = 1
+ else:
+ clist[x]['slave'] = 0
+
+ _page = {}
+ _page['count'] = count
+ _page['p'] = page
+ _page['row'] = page_size
+ _page['tojs'] = 'dbList'
+ data['page'] = mw.getPage(_page)
+ data['data'] = clist
+
+ return mw.getJson(data)
+
+
+def setDbMaster(version):
+ args = getArgs()
+ data = checkArgs(args, ['name'])
+ if not data[0]:
+ return data[1]
+
+ conf = getConf()
+ con = mw.readFile(conf)
+ rep = r"(binlog-do-db\s*?=\s*?(.*))"
+ dodb = re.findall(rep, con, re.M)
+
+ isHas = False
+ for x in range(0, len(dodb)):
+
+ if dodb[x][1] == args['name']:
+ isHas = True
+
+ con = con.replace(dodb[x][0] + "\n", '')
+ mw.writeFile(conf, con)
+
+ if not isHas:
+ prefix = '#binlog-do-db'
+ con = con.replace(
+ prefix, prefix + "\nbinlog-do-db=" + args['name'])
+ mw.writeFile(conf, con)
+
+ restart(version)
+ time.sleep(4)
+ return mw.returnJson(True, '设置成功', [args, dodb])
+
+
+def setDbSlave(version):
+ args = getArgs()
+ data = checkArgs(args, ['name'])
+ if not data[0]:
+ return data[1]
+
+ conf = getConf()
+ con = mw.readFile(conf)
+ rep = r"(replicate-do-db\s*?=\s*?(.*))"
+ dodb = re.findall(rep, con, re.M)
+
+ isHas = False
+ for x in range(0, len(dodb)):
+ if dodb[x][1] == args['name']:
+ isHas = True
+
+ con = con.replace(dodb[x][0] + "\n", '')
+ mw.writeFile(conf, con)
+
+ if not isHas:
+ prefix = '#replicate-do-db'
+ con = con.replace(
+ prefix, prefix + "\nreplicate-do-db=" + args['name'])
+ mw.writeFile(conf, con)
+
+ restart(version)
+ time.sleep(4)
+ return mw.returnJson(True, '设置成功', [args, dodb])
+
+
+def getMasterStatus(version=''):
+
+ if status(version) == 'stop':
+ return mw.returnJson(false, 'MySQL未启动,或正在启动中...!', [])
+
+ conf = getConf()
+ con = mw.readFile(conf)
+ master_status = False
+ if con.find('#log-bin') == -1 and con.find('log-bin') > 1:
+ dodb = findBinlogDoDb()
+ if len(dodb) > 0:
+ master_status = True
+ data = {}
+ data['status'] = master_status
+
+ db = pMysqlDb()
+ dlist = db.query('show slave status')
+ # print(dlist, len(dlist))
+ if len(dlist) > 0 and (dlist[0][10] == 'Yes' or dlist[0][11] == 'Yes'):
+ data['slave_status'] = True
+
+ return mw.returnJson(master_status, '设置成功', data)
+
+
+def setMasterStatus(version=''):
+
+ conf = getConf()
+ con = mw.readFile(conf)
+
+ if con.find('#log-bin') != -1:
+ return mw.returnJson(False, '必须开启二进制日志')
+
+ sign = 'mdserver_ms_open'
+
+ dodb = findBinlogDoDb()
+ if not sign in dodb:
+ prefix = '#binlog-do-db'
+ con = con.replace(prefix, prefix + "\nbinlog-do-db=" + sign)
+ mw.writeFile(conf, con)
+ else:
+ con = con.replace("binlog-do-db=" + sign + "\n", '')
+ rep = r"(binlog-do-db\s*?=\s*?(.*))"
+ dodb = re.findall(rep, con, re.M)
+ for x in range(0, len(dodb)):
+ con = con.replace(dodb[x][0] + "\n", '')
+ mw.writeFile(conf, con)
+
+ restart(version)
+ return mw.returnJson(True, '设置成功')
+
+
+def getMasterRepSlaveList(version=''):
+ args = getArgs()
+ page = 1
+ page_size = 10
+ search = ''
+ data = {}
+ if 'page' in args:
+ page = int(args['page'])
+
+ if 'page_size' in args:
+ page_size = int(args['page_size'])
+
+ if 'search' in args:
+ search = args['search']
+
+ conn = pSqliteDb('master_replication_user')
+ limit = str((page - 1) * page_size) + ',' + str(page_size)
+ condition = ''
+
+ if not search == '':
+ condition = "name like '%" + search + "%'"
+ field = 'id,username,password,accept,ps,addtime'
+ clist = conn.where(condition, ()).field(
+ field).limit(limit).order('id desc').select()
+ count = conn.where(condition, ()).count()
+
+ _page = {}
+ _page['count'] = count
+ _page['p'] = page
+ _page['row'] = page_size
+ _page['tojs'] = 'getMasterRepSlaveList'
+ data['page'] = mw.getPage(_page)
+ data['data'] = clist
+
+ return mw.getJson(data)
+
+
+def addMasterRepSlaveUser(version=''):
+ args = getArgs()
+ data = checkArgs(args,
+ ['username', 'password'])
+ if not data[0]:
+ return data[1]
+
+ if not 'address' in args:
+ address = ''
+ else:
+ address = args['address'].strip()
+
+ username = args['username'].strip()
+ password = args['password'].strip()
+ # ps = args['ps'].strip()
+ # address = args['address'].strip()
+ # dataAccess = args['dataAccess'].strip()
+
+ reg = "^[\w\.-]+$"
+ if not re.match(reg, username):
+ return mw.returnJson(False, '用户名不能带有特殊符号!')
+ checks = ['root', 'mysql', 'test', 'sys', 'panel_logs']
+ if username in checks or len(username) < 1:
+ return mw.returnJson(False, '用户名不合法!')
+ if password in checks or len(password) < 1:
+ return mw.returnJson(False, '密码不合法!')
+
+ if len(password) < 1:
+ password = mw.md5(time.time())[0:8]
+
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('master_replication_user')
+
+ if psdb.where("username=?", (username)).count():
+ return mw.returnJson(False, '用户已存在!')
+
+ result = pdb.execute("GRANT REPLICATION SLAVE ON *.* TO '" +
+ username + "'@'%' identified by '" + password + "';FLUSH PRIVILEGES;")
+ # print result
+ isError = isSqlError(result)
+ if isError != None:
+ return isError
+
+ addTime = time.strftime('%Y-%m-%d %X', time.localtime())
+ psdb.add('username,password,accept,ps,addtime',
+ (username, password, '%', '', addTime))
+ return mw.returnJson(True, '添加成功!')
+
+
+def getMasterRepSlaveUserCmd(version):
+ args = getArgs()
+ data = checkArgs(args, ['username', 'db'])
+ if not data[0]:
+ return data[1]
+
+ psdb = pSqliteDb('master_replication_user')
+ f = 'username,password'
+ if args['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(
+ '1').order('id desc').select()
+
+ ip = mw.getLocalIp()
+ port = getMyPort()
+
+ db = pMysqlDb()
+ tmp = db.query('show master status')
+
+ if len(tmp) == 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='" + tmp[0][0] + \
+ "',MASTER_LOG_POS=" + str(tmp[0][1]) + ""
+
+ # if args['db'] != '':
+ # replicate-do-table
+
+ return mw.returnJson(True, 'OK!', sql)
+
+
+def delMasterRepSlaveUser(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['username'])
+ if not data[0]:
+ return data[1]
+
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('master_replication_user')
+ pdb.execute("drop user '" + args['username'] + "'@'%'")
+ psdb.where("username=?", (args['username'],)).delete()
+
+ return mw.returnJson(True, '删除成功!')
+
+
+def updateMasterRepSlaveUser(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['username', 'password'])
+ if not data[0]:
+ return data[1]
+
+ pdb = pMysqlDb()
+ psdb = pSqliteDb('master_replication_user')
+ pdb.execute("drop user '" + args['username'] + "'@'%'")
+
+ pdb.execute("GRANT REPLICATION SLAVE ON *.* TO '" +
+ args['username'] + "'@'%' identified by '" + args['password'] + "'")
+
+ psdb.where("username=?", (args['username'],)).save(
+ 'password', args['password'])
+
+ return mw.returnJson(True, '更新成功!')
+
+
+def getSlaveList(version=''):
+
+ db = pMysqlDb()
+ dlist = db.query('show slave status')
+
+ # print(dlist)
+ ret = []
+ for x in range(0, len(dlist)):
+ tmp = {}
+ tmp['Master_User'] = dlist[x][2]
+ tmp['Master_Host'] = dlist[x][1]
+ tmp['Master_Port'] = dlist[x][3]
+ tmp['Master_Log_File'] = dlist[x][5]
+ tmp['Slave_IO_Running'] = dlist[x][10]
+ tmp['Slave_SQL_Running'] = dlist[x][11]
+ ret.append(tmp)
+ data = {}
+ data['data'] = ret
+
+ return mw.getJson(data)
+
+
+def setSlaveStatus(version=''):
+ db = pMysqlDb()
+ dlist = db.query('show slave status')
+
+ if len(dlist) == 0:
+ return mw.returnJson(False, '需要手动添加主服务同步命令!')
+
+ if len(dlist) > 0 and (dlist[0][10] == 'Yes' or dlist[0][11] == 'Yes'):
+ db.query('stop slave')
+ else:
+ db.query('start slave')
+
+ return mw.returnJson(True, '设置成功!')
+
+
+def deleteSlave(version=''):
+ db = pMysqlDb()
+ dlist = db.query('stop slave;reset slave all')
+ return mw.returnJson(True, '删除成功!')
+
+
+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':
+ dlist = findBinlogDoDb()
+ cmd = getServerDir() + "/bin/mysqldump -uroot -p" + \
+ pwd + " --databases " + ' '.join(dlist) + \
+ " > /tmp/dump.sql"
+ else:
+ cmd = getServerDir() + "/bin/mysqldump -uroot -p" + pwd + \
+ " --databases " + args['db'] + " > /tmp/dump.sql"
+
+ 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 doFullSync():
+
+ args = getArgs()
+ data = checkArgs(args, ['db'])
+ if not data[0]:
+ return data[1]
+
+ 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][1]
+ print(ip)
+
+ status_file = '/tmp/db_async_status.txt'
+
+ status_data['code'] = 0
+ status_data['msg'] = '运行中...'
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ import paramiko
+ paramiko.util.log_to_file('paramiko.log')
+ ssh = paramiko.SSHClient()
+
+ SSH_PRIVATE_KEY = '/root/.ssh/id_rsa'
+
+ if mw.getOs() == 'darwin':
+ user = mw.execShell(
+ "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
+ SSH_PRIVATE_KEY = '/Users/' + user + '/.ssh/id_rsa'
+
+ print(SSH_PRIVATE_KEY)
+ if not os.path.exists(SSH_PRIVATE_KEY):
+ status_data['code'] = 0
+ status_data['msg'] = '需要配置免登录...'
+ mw.writeFile(status_file, json.dumps(status_data))
+ return
+
+ try:
+ key = paramiko.RSAKey.from_private_key_file(SSH_PRIVATE_KEY)
+ # ssh.load_system_host_keys()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ ssh.connect(hostname=ip, port=22, username='root', pkey=key)
+ except Exception as e:
+ status_data['code'] = 0
+ status_data['msg'] = '需要配置免登录....'
+ mw.writeFile(status_file, json.dumps(status_data))
+ return
+
+ cmd = "cd /www/server/mdserver-web && python /www/server/mdserver-web/plugins/mysql/index.py dump_mysql_data {\"db\":'" + args[
+ 'db'] + "'}"
+ stdin, stdout, stderr = ssh.exec_command(cmd)
+ result = stdout.read()
+ result_err = stderr.read()
+
+ if result == 'ok':
+ status_data['code'] = 1
+ status_data['msg'] = '主服务器备份完成...'
+ status_data['progress'] = 30
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ r = mw.execShell('scp root@' + ip + ':/tmp/dump.sql /tmp')
+ if r[0] == '':
+ status_data['code'] = 2
+ status_data['msg'] = '数据同步本地完成...'
+ status_data['progress'] = 40
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ cmd = 'cd /www/server/mdserver-web && python /www/server/mdserver-web/plugins/mysql/index.py get_master_rep_slave_user_cmd {"username":"","db":""}'
+ stdin, stdout, stderr = ssh.exec_command(cmd)
+ result = stdout.read()
+ result_err = stderr.read()
+ cmd_data = json.loads(result)
+
+ db.query('stop slave')
+ status_data['code'] = 3
+ status_data['msg'] = '停止从库完成...'
+ status_data['progress'] = 45
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ dlist = db.query(cmd_data['data'])
+ status_data['code'] = 4
+ status_data['msg'] = '刷新库信息完成...'
+ status_data['progress'] = 50
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
+ cmd = getServerDir() + "/bin/mysql -uroot -p" + pwd + " < /tmp/dump.sql"
+ print(mw.execShell(cmd))
+ status_data['code'] = 5
+ status_data['msg'] = '同步数据完成...'
+ status_data['progress'] = 90
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ db.query('start slave')
+ status_data['code'] = 6
+ status_data['msg'] = '从库重启完成...'
+ status_data['progress'] = 100
+ mw.writeFile(status_file, json.dumps(status_data))
+
+ return True
+
+
+def fullSync(version=''):
+ args = getArgs()
+ data = checkArgs(args, ['db', 'begin'])
+ if not data[0]:
+ return data[1]
+
+ status_file = '/tmp/db_async_status.txt'
+ if args['begin'] == '1':
+ cmd = 'cd ' + mw.getRunDir() + ' && python ' + \
+ getPluginDir() + \
+ '/index.py do_full_sync {"db":"' + args['db'] + '"} &'
+ mw.execShell(cmd)
+ return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
+
+ if os.path.exists(status_file):
+ c = mw.readFile(status_file)
+ d = json.loads(c)
+
+ if d['code'] == 6:
+ os.remove(status_file)
+ return c
+
+ return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
+
+
+# 安装预检查
+def installPreInspection(version):
+ sys = mw.execShell(
+ "cat /etc/*-release | grep PRETTY_NAME |awk -F = '{print $2}' | awk -F '\"' '{print $2}'| awk '{print $1}'")
+
+ sys_id = mw.execShell(
+ "cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
+
+ sysName = sys[0].strip().lower()
+ sysId = sys_id[0].strip()
+
+ if not sysName in ('ubuntu', 'debian'):
+ return '仅支持ubuntu,debian'
+
+ if sysName == 'centos':
+ if version == '5.7' and int(sysId) > 7:
+ return 'MySQL[' + version + ']不支持安装在ceonts[' + sysId + ']'
+ if version == '8.0' and int(sysId) < 6:
+ return 'MySQL[' + version + ']不支持安装在ceonts[' + sysId + ']'
+ return 'ok'
+
+if __name__ == "__main__":
+ func = sys.argv[1]
+
+ version = "5.6"
+ if (len(sys.argv) > 2):
+ version = sys.argv[2]
+
+ 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 == 'install_pre_inspection':
+ print(installPreInspection(version))
+ elif func == 'initd_status':
+ print(initdStatus())
+ elif func == 'initd_install':
+ print(initdInstall())
+ elif func == 'initd_uninstall':
+ print(initdUinstall())
+ elif func == 'run_info':
+ print(runInfo())
+ elif func == 'db_status':
+ print(myDbStatus())
+ elif func == 'set_db_status':
+ print(setDbStatus())
+ elif func == 'conf':
+ print(getConf())
+ elif func == 'bin_log':
+ print(binLog())
+ elif func == 'error_log':
+ print(getErrorLog())
+ elif func == 'show_log':
+ print(getShowLogFile())
+ elif func == 'my_db_pos':
+ print(getMyDbPos())
+ elif func == 'set_db_pos':
+ print(setMyDbPos())
+ elif func == 'my_port':
+ print(getMyPort())
+ elif func == 'set_my_port':
+ print(setMyPort())
+ elif func == 'init_pwd':
+ print(initMysqlPwd())
+ elif func == 'get_db_list':
+ print(getDbList())
+ elif func == 'set_db_backup':
+ print(setDbBackup())
+ elif func == 'import_db_backup':
+ print(importDbBackup())
+ elif func == 'delete_db_backup':
+ print(deleteDbBackup())
+ elif func == 'get_db_backup_list':
+ print(getDbBackupList())
+ elif func == 'add_db':
+ print(addDb())
+ elif func == 'del_db':
+ print(delDb())
+ elif func == 'sync_get_databases':
+ print(syncGetDatabases())
+ elif func == 'sync_to_databases':
+ print(syncToDatabases())
+ elif func == 'set_root_pwd':
+ print(setRootPwd())
+ elif func == 'set_user_pwd':
+ print(setUserPwd())
+ elif func == 'get_db_access':
+ print(getDbAccess())
+ elif func == 'set_db_access':
+ print(setDbAccess())
+ elif func == 'set_db_ps':
+ print(setDbPs())
+ elif func == 'get_db_info':
+ print(getDbInfo())
+ elif func == 'repair_table':
+ print(repairTable())
+ elif func == 'opt_table':
+ print(optTable())
+ elif func == 'alter_table':
+ print(alterTable())
+ elif func == 'get_total_statistics':
+ print(getTotalStatistics())
+ elif func == 'get_masterdb_list':
+ print(getMasterDbList(version))
+ elif func == 'get_master_status':
+ print(getMasterStatus(version))
+ elif func == 'set_master_status':
+ print(setMasterStatus(version))
+ elif func == 'set_db_master':
+ print(setDbMaster(version))
+ elif func == 'set_db_slave':
+ print(setDbSlave(version))
+ elif func == 'get_master_rep_slave_list':
+ print(getMasterRepSlaveList(version))
+ elif func == 'add_master_rep_slave_user':
+ print(addMasterRepSlaveUser(version))
+ elif func == 'del_master_rep_slave_user':
+ print(delMasterRepSlaveUser(version))
+ elif func == '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 == '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())
+ elif func == 'dump_mysql_data':
+ print(dumpMysqlData(version))
+ else:
+ print('error')
diff --git a/plugins/mysql-apt/info.json b/plugins/mysql-apt/info.json
new file mode 100755
index 000000000..db2e5035f
--- /dev/null
+++ b/plugins/mysql-apt/info.json
@@ -0,0 +1,17 @@
+{
+ "title":"MySQL[APT]",
+ "tip":"soft",
+ "name":"mysql-apt",
+ "type":"运行环境",
+ "ps":"[开发中..不要使用]一种关系数据库管理系统(极速安装)[YUM|APT]!",
+ "todo_versions":["5.7","8.0"],
+ "versions":["5.7","8.0"],
+ "shell":"install.sh",
+ "install_pre_inspection":true,
+ "checks":"server/mysql-apt",
+ "path":"server/mysql-apt",
+ "author":"mysql",
+ "home":"https://dev.mysql.com/downloads/mysql",
+ "date":"2022-06-29",
+ "pid": "6"
+}
\ No newline at end of file
diff --git a/plugins/mysql-apt/init.d/mysql.service.tpl b/plugins/mysql-apt/init.d/mysql.service.tpl
new file mode 100644
index 000000000..a068c3716
--- /dev/null
+++ b/plugins/mysql-apt/init.d/mysql.service.tpl
@@ -0,0 +1,50 @@
+# Copyright (c) 2015, 2022, Oracle and/or its affiliates.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2.0,
+# as published by the Free Software Foundation.
+#
+# This program is also distributed with certain software (including
+# but not limited to OpenSSL) that is licensed under separate terms,
+# as designated in a particular file or component or in included license
+# documentation. The authors of MySQL hereby grant you an additional
+# permission to link the program and your derivative works with the
+# separately licensed software that they have included with MySQL.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License, version 2.0, for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# MySQL systemd service file
+
+[Unit]
+Description=MySQL Community Server
+Documentation=man:mysqld(8)
+Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
+After=network.target
+
+[Install]
+WantedBy=multi-user.target
+
+[Service]
+User=mysql
+Group=mysql
+Type=notify
+ExecStartPre=+/usr/share/mysql-8.0/mysql-systemd-start pre
+ExecStart=/usr/sbin/mysqld
+TimeoutSec=0
+LimitNOFILE = 10000
+Restart=on-failure
+RestartPreventExitStatus=1
+
+# Always restart when mysqld exits with exit code of 16. This special exit code
+# is used by mysqld for RESTART SQL.
+RestartForceExitStatus=16
+
+# Set enviroment variable MYSQLD_PARENT_PID. This is required for restart.
+Environment=MYSQLD_PARENT_PID=1
diff --git a/plugins/mysql-apt/install.sh b/plugins/mysql-apt/install.sh
new file mode 100755
index 000000000..d24036745
--- /dev/null
+++ b/plugins/mysql-apt/install.sh
@@ -0,0 +1,47 @@
+#!/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")
+
+# curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
+
+# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh install 8.0
+# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh uninstall 8.0
+# cd /www/server/mdserver-web && python3 /www/server/mdserver-web/plugins/mysql-apt/index.py start 8.0
+
+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
+
+ cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py stop ${type}
+ cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py initd_uninstall ${type}
+ cd $curPath
+fi
+
+sh -x $curPath/versions/$2/install.sh $1
+
+if [ "${action}" == "install" ];then
+# #初始化
+ cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py start ${type}
+ cd ${rootPath} && python3 ${rootPath}/plugins/mysql-apt/index.py initd_install ${type}
+fi
diff --git a/plugins/mysql-apt/js/mysql-apt.js b/plugins/mysql-apt/js/mysql-apt.js
new file mode 100755
index 000000000..eeae4c3e1
--- /dev/null
+++ b/plugins/mysql-apt/js/mysql-apt.js
@@ -0,0 +1,1735 @@
+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:'mysql-apt', 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:'mysql-apt', 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-ya', 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 = '