Compare commits

..
404 Commits
Author SHA1 Message Date
Mr Chen a1b3e70816 Merge pull request #531 from midoks/dev
0.16.4
2024-04-04 12:32:06 +08:00
Mr Chen 6f4479558f Update README.md 2024-04-04 12:31:17 +08:00
Mr Chen f817792aeb Update config_api.py 2024-04-04 12:29:34 +08:00
Mr Chen c8c0e44143 Update op_waf.js 2024-04-04 12:26:29 +08:00
Mr Chen 6668c2e14b update 2024-04-04 11:42:19 +08:00
Mr Chen 721f041c65 Update README.md 2024-04-04 00:20:05 +08:00
Mr Chen 87239f5361 Merge pull request #530 from midoks/dev
更新为支付宝
2024-04-04 00:18:55 +08:00
Mr Chen b48e3cbfcc update 2024-04-04 00:17:58 +08:00
Mr Chen 4b41c6df57 update 2024-04-02 00:17:20 +08:00
Mr Chen b491a6e913 Update README.md 2024-03-29 15:38:01 +08:00
Mr Chen 42271c5562 Merge pull request #529 from midoks/dev
discord
2024-03-29 15:30:24 +08:00
Mr Chen ef63465aea Update README.md 2024-03-29 15:28:40 +08:00
Mr Chen 98745e8134 Merge pull request #528 from midoks/dev
简单优化+ whatapp
2024-03-29 11:21:41 +08:00
Mr Chen 2fb293c89c Update README.md 2024-03-29 11:20:59 +08:00
Mr Chen 4e0db8d0a1 Update commit.tpl.ssh 2024-03-27 21:11:53 +08:00
Mr Chen 4b1e40b42d Update index.html 2024-03-26 17:47:26 +08:00
Mr Chen 935bee90f7 Update index.html 2024-03-26 17:42:25 +08:00
Mr Chen 0489a9df2c Update config_api.py 2024-03-19 23:29:27 +08:00
Mr Chen 20a4154240 update 2024-03-19 23:27:17 +08:00
Mr Chen a8ced31d32 Update mw.py 2024-03-19 23:24:40 +08:00
Mr Chen ac97b8f7ec Update tools.py 2024-03-19 23:21:19 +08:00
Mr Chen a797cd3741 Update push_notice_msg.py 2024-03-18 15:42:27 +08:00
Mr Chen a616736bf1 Merge pull request #526 from midoks/dev
AD及 二次验证
2024-03-18 15:26:22 +08:00
Mr Chen 8a90f5cb90 ad 2024-03-18 15:25:30 +08:00
Mr Chen 419d4abe8e Update login.html 2024-03-10 19:21:18 +08:00
Mr Chen ba555fba63 Update __init__.py 2024-03-10 19:16:05 +08:00
Mr Chen 7ead8708bc Update __init__.py 2024-03-10 19:15:42 +08:00
Mr Chen bd5b066afe Update __init__.py 2024-03-10 19:10:57 +08:00
Mr Chen 6d08c160e0 Update __init__.py 2024-03-10 19:10:27 +08:00
Mr Chen f24f8a3a16 Update config_api.py 2024-03-10 18:35:05 +08:00
Mr Chen 707b0d4b53 Update tools.py 2024-03-10 18:34:26 +08:00
Mr Chen d19e9cd8f4 二次验证,加强安全登录 2024-03-10 18:27:39 +08:00
Mr Chen a2d0cc6cfe Update requirements.txt 2024-03-10 14:43:53 +08:00
Mr Chen 356fd831fb Update requirements.txt 2024-03-10 14:33:09 +08:00
Mr Chen ec4988e732 update 2024-02-19 18:41:32 +08:00
Mr Chen 3a694b8d7d ad
# 海外服务器 高防CDN 解决移动屏蔽 | 19/m | next,2/19 | @YYCDNFW
2024-02-19 18:35:37 +08:00
Mr Chen d5945fd449 Merge pull request #524 from midoks/dev
更换GitHub Proxy
2024-02-08 16:47:46 +08:00
Mr Chen 10186786d9 更换GitHub Proxy
更换GitHub Proxy
2024-02-08 16:46:43 +08:00
Mr Chen 0eb8791e84 Merge pull request #523 from midoks/dev
Update sql_mysql.py
2024-02-07 01:57:51 +08:00
Mr Chen 5234b55798 Update sql_mysql.py 2024-02-07 01:54:30 +08:00
Mr Chen 4efe740504 Merge pull request #522 from midoks/dev
0.16.3
2024-02-06 22:53:11 +08:00
Mr Chen bde0ed59ad Update README.md 2024-02-06 22:52:15 +08:00
Mr Chen 19c855790f Update config_api.py 2024-02-06 22:51:47 +08:00
Mr Chen 4a90f1b8b0 Update app.js 2024-02-06 22:45:25 +08:00
Mr Chen f83bdffed8 update 2024-02-06 22:44:52 +08:00
Mr Chen 087cb4fc37 Update app.js 2024-02-06 22:16:09 +08:00
Mr Chen 66bcd15502 update 2024-02-06 22:14:17 +08:00
Mr Chen 29e3dedbe9 update 2024-02-06 22:11:02 +08:00
Mr Chen f10160c239 update 2024-02-06 22:06:26 +08:00
Mr Chen 376d09a955 up 2024-02-06 21:31:20 +08:00
Mr Chen 9076a3a11a Update app.js 2024-02-06 21:27:05 +08:00
Mr Chen 57719990d5 Update app.js 2024-02-06 21:20:07 +08:00
Mr Chen 7073d66662 Update app.js 2024-02-06 21:18:33 +08:00
Mr Chen 1983d02107 up 2024-02-06 21:17:24 +08:00
Mr Chen b4acb2942f update 2024-02-06 19:49:15 +08:00
Mr Chen c94a662235 Update index.html 2024-02-06 18:25:47 +08:00
Mr Chen 1d61026dd3 Update index.html 2024-02-06 18:25:28 +08:00
Mr Chen 48a55e279e Update nosql_mongodb.py 2024-02-06 18:06:45 +08:00
Mr Chen 55e9313711 update 2024-02-06 18:00:20 +08:00
Mr Chen 5ab59c3b75 update 2024-02-06 04:34:41 +08:00
Mr Chen 9c045b8e85 update 2024-02-06 04:10:13 +08:00
Mr Chen 65e87fec1a up 2024-02-06 03:52:36 +08:00
Mr Chen dc8f508ac5 update 2024-02-06 03:14:20 +08:00
Mr Chen ce0c2fb9ea Update index.py 2024-02-05 00:22:00 +08:00
Mr Chen d7e70aa701 Update index.py 2024-02-05 00:17:44 +08:00
Mr Chen ceacaaf7ae Update index.py 2024-02-04 18:12:33 +08:00
Mr Chen 36ad902250 Update tool_migrate.py 2024-02-04 15:30:05 +08:00
Mr Chen 7a871d3e16 Update tool_migrate.py 2024-02-04 15:29:31 +08:00
Mr Chen f36ba4a351 Update tool_migrate.py 2024-02-04 15:27:50 +08:00
Mr Chen 5093265a24 Update index.html 2024-02-04 02:38:03 +08:00
Mr Chen 9c4347f692 del rockmongo 2024-02-03 23:30:52 +08:00
Mr Chen cb882ab7a1 Update requirements.txt 2024-02-03 20:36:40 +08:00
Mr Chen 0d5fd1b423 Update README.md 2024-02-03 18:46:13 +08:00
Mr Chen e694635088 Update README.md 2024-02-03 18:45:59 +08:00
Mr Chen 3386ae2064 Update app.js 2024-02-03 16:11:00 +08:00
Mr Chen bbaced5976 Update app.js 2024-02-03 15:51:33 +08:00
Mr Chen c0d5c5c0e6 Update app.js 2024-02-03 15:50:38 +08:00
Mr Chen f9f7de48ef Update app.js 2024-02-03 15:43:26 +08:00
Mr Chen 5555eab5c0 Update stats.js 2024-02-03 15:40:35 +08:00
Mr Chen 654737cbd2 Update setting.js 2024-02-03 15:34:38 +08:00
Mr Chen 04568df3df update 2024-02-03 04:44:06 +08:00
Mr Chen b1e8839ace update_dev 2024-02-03 04:09:00 +08:00
Mr Chen 80c6f91206 update 2024-02-02 06:16:28 +08:00
Mr Chen 315b8e0e48 Update index.html 2024-02-01 22:18:18 +08:00
Mr Chen ed295d5456 up 2024-02-01 22:08:45 +08:00
Mr Chen eb38d81674 Update config_api.py 2024-02-01 15:06:39 +08:00
Mr Chen 0bc3b42819 del phpredisadmin 2024-02-01 05:19:10 +08:00
Mr Chen 8a640981d2 数据管理插件 2024-02-01 05:09:56 +08:00
Mr Chen 7b94a61b65 update 2024-01-29 19:25:05 +08:00
Mr Chen e24151f332 Update public.js 2024-01-27 15:45:05 +08:00
Mr Chen dc43953c05 Update public.js 2024-01-27 15:44:52 +08:00
Mr Chen 160ff6a4a7 update 2024-01-26 03:03:07 +08:00
Mr Chen a218ba05d2 Update app_start.php 2024-01-25 15:38:32 +08:00
Mr Chen 65cb4941af Update index.py 2024-01-25 15:11:18 +08:00
Mr Chen 53a12e7c4b Update site.js 2024-01-24 19:25:29 +08:00
Mr Chen 6db8a906ff Update task.py 2024-01-23 23:41:06 +08:00
Mr Chen fc6c86e3ce Update info.json 2024-01-23 03:02:04 +08:00
Mr Chen f5989c881d Update info.json 2024-01-23 03:00:50 +08:00
Mr Chen b4946a87ee Update index.py 2024-01-23 02:43:58 +08:00
Mr Chen 562e153371 Update site.css 2024-01-23 02:01:13 +08:00
Mr Chen 63ea0cc129 Update requirements.txt 2024-01-23 00:16:03 +08:00
Mr Chen 8eacae7c6a Update .gitignore 2024-01-22 23:46:30 +08:00
Mr Chen 3e48c3871a Update task.py 2024-01-22 23:46:15 +08:00
Mr Chen 22df4cb5b1 Update task.py 2024-01-22 23:41:02 +08:00
Mr Chen 2d5d954586 Create ico.png 2024-01-22 16:48:14 +08:00
Mr Chen 63ce3805ee Update index.py 2024-01-22 00:23:55 +08:00
Mr Chen 3fe4918b55 update 2024-01-22 00:16:25 +08:00
Mr Chen 24cc733e45 Update mongodb.conf 2024-01-21 23:30:52 +08:00
Mr Chen 1ebb9e1ff3 Update mongodb.conf 2024-01-21 22:15:08 +08:00
Mr Chen 9769f2c190 Update config_api.py 2024-01-21 16:34:28 +08:00
Mr Chen de91e4545b update 2024-01-21 16:01:10 +08:00
Mr Chen 8d3c87a25e Update opcache.sh 2024-01-21 15:54:00 +08:00
Mr Chen 660e393cf1 Update install.sh 2024-01-21 13:47:35 +08:00
Mr Chen fa5f2d6de5 Update config.js 2024-01-21 02:35:15 +08:00
Mr Chen f27406d343 Update config.js 2024-01-21 02:32:37 +08:00
Mr Chen 488577af68 update 2024-01-21 02:23:18 +08:00
Mr Chen 0f7b462b43 Update task.py 2024-01-21 01:47:41 +08:00
Mr Chen 998f1ceae5 Update task.py 2024-01-21 01:44:17 +08:00
Mr Chen 2a9bec3fb8 Update README.md 2024-01-21 01:29:08 +08:00
Mr Chen 5c301296df 站点页优化 2024-01-21 01:27:09 +08:00
Mr Chen 45b0e94132 update 2024-01-20 18:32:35 +08:00
Mr Chen 06be751d1a update 2024-01-20 18:25:31 +08:00
Mr Chen f939b03a0b Update update_dev.sh 2024-01-20 18:22:35 +08:00
Mr Chen 3339406f37 Update compatibility.md 2024-01-20 13:57:24 +08:00
Mr Chen f32d07ccc9 Update nginx.conf 2024-01-20 13:09:40 +08:00
Mr Chen ab8f1623bf update 2024-01-20 02:31:29 +08:00
Mr Chen d467d73230 Update backup.conf 2024-01-20 02:30:52 +08:00
Mr Chen 4b0dd7d3fb Update php.js 2024-01-20 01:49:35 +08:00
Mr Chen 91d243f8b1 Update install.sh 2024-01-20 01:37:57 +08:00
Mr Chen d682882d25 Update install.sh 2024-01-20 01:37:07 +08:00
Mr Chen 0b3745c933 Update README.md 2024-01-20 01:29:45 +08:00
Mr Chen 935c3012f9 Update README.md 2024-01-20 01:08:45 +08:00
Mr Chen a191548a83 Update enable-php-upstream.conf 2024-01-19 22:06:48 +08:00
Mr Chen 9a01d61e1e Update enable-php.conf 2024-01-19 22:06:35 +08:00
Mr Chen 7524798385 php配置改造 2024-01-19 21:21:36 +08:00
Mr Chen 86e3796524 Update logs_api.py 2024-01-18 13:23:22 +08:00
Mr Chen 37d68f5ff8 Update logs_api.py 2024-01-17 21:19:48 +08:00
Mr Chen 647e3904d2 Create enable-php-upstream.conf 2024-01-17 04:22:34 +08:00
Mr Chen c5abb3eea1 Update index.html 2024-01-17 03:20:48 +08:00
Mr Chen 65c94c64ae Update README.md 2024-01-17 02:47:12 +08:00
Mr Chen dbc132951b PHP-FPM设置多个应用池 2024-01-17 02:44:17 +08:00
Mr Chen 440ba49e7b Create backup.conf 2024-01-17 00:07:45 +08:00
Mr Chen 6a0f78b1a0 Update index.html 2024-01-17 00:07:30 +08:00
Mr Chen a69ff3e373 php更新加密校验 2024-01-16 01:18:27 +08:00
Mr Chen 770d37e575 Update config_api.py 2024-01-15 19:58:33 +08:00
Mr Chen e725ad90ca Update config.js 2024-01-15 19:56:57 +08:00
Mr Chen bf5d8f7f27 Update commit.tpl 2024-01-15 17:14:46 +08:00
Mr Chen 9bc72b23d6 Update commit.tpl 2024-01-15 17:13:52 +08:00
Mr Chen 3ac3350240 Update install.sh 2024-01-14 22:38:40 +08:00
Mr Chen c1d04b0a16 Update index.py 2024-01-14 22:35:48 +08:00
Mr Chen 1962cece21 Update index.py 2024-01-14 22:33:00 +08:00
Mr Chen 0d24b8aebd update 2024-01-14 22:29:28 +08:00
Mr Chen de50de0a75 Update index.py 2024-01-14 22:16:35 +08:00
Mr Chen 190fc88d4f Update index.py 2024-01-10 22:23:44 +08:00
Mr Chen 727a7872a7 Update index.py 2024-01-10 14:52:19 +08:00
Mr Chen d408d56826 Update README.md 2024-01-10 14:14:17 +08:00
Mr Chen 1cccd63edc update 2024-01-10 12:57:43 +08:00
Mr Chen cc50816286 Update config.html 2024-01-10 00:55:53 +08:00
Mr Chen 04426c7a67 Update README.md 2024-01-10 00:40:27 +08:00
Mr Chen 3979820eae 时区 2024-01-10 00:19:09 +08:00
Mr Chen 3a850a31a1 Update config_api.py 2024-01-10 00:05:52 +08:00
Mr Chen 6f5487b487 Update requirements.txt 2024-01-10 00:03:59 +08:00
Mr Chen d09a96ec84 时区设置 2024-01-10 00:02:04 +08:00
Mr Chen dcc4e14e7b Update gd.sh 2024-01-09 19:48:29 +08:00
Mr Chen e947b8db4e Update gd_old.sh 2024-01-09 19:47:51 +08:00
Mr Chen 158a66ab62 update 2024-01-09 19:06:34 +08:00
Mr Chen df596fc673 Update tools.py 2024-01-09 01:57:28 +08:00
Mr Chen 707fd668d5 update 2024-01-09 01:56:25 +08:00
Mr Chen b96c4c00e3 Update common.py 2024-01-09 01:12:13 +08:00
Mr Chen bc6cf72cfe up 2024-01-07 19:16:24 +08:00
Mr Chen 48dacb4c27 Update php.js 2024-01-07 04:14:03 +08:00
Mr Chen 78c9abbde2 update 2024-01-07 04:12:33 +08:00
Mr Chen d8d772c6dc Create trace.sh 2024-01-07 03:16:18 +08:00
Mr Chen 33e114ffdd Update php.js 2024-01-07 03:11:18 +08:00
Mr Chen 552b63d329 update 2024-01-07 03:08:41 +08:00
Mr Chen 36637260a7 Update index_php_apt.py 2024-01-07 03:06:45 +08:00
Mr Chen 53fbb5039b Update index_php_apt.py 2024-01-07 02:58:50 +08:00
Mr Chen 74152af289 Update index_php_apt.py 2024-01-07 02:56:30 +08:00
Mr Chen 5bf4401fb0 Update index_php_apt.py 2024-01-07 02:51:56 +08:00
Mr Chen 12117a3b27 Update index_php_apt.py 2024-01-07 02:47:58 +08:00
Mr Chen d726f1bb15 Update php.js 2024-01-07 02:43:33 +08:00
Mr Chen a2b316b4d2 update 2024-01-07 02:40:56 +08:00
Mr Chen 0d48e5250a Update php.js 2024-01-07 02:35:21 +08:00
Mr Chen d3cd606432 Update php.js 2024-01-07 02:35:14 +08:00
Mr Chen 600435f23c update 2024-01-07 02:34:33 +08:00
Mr Chen b4831d64b9 php界面优化 2024-01-07 02:32:04 +08:00
Mr Chen 6638967636 Create script.sh 2024-01-07 02:05:19 +08:00
Mr Chen ead409a58c Update linux.conf 2024-01-07 01:32:15 +08:00
Mr Chen 971da145cb Update linux.conf 2024-01-07 01:21:59 +08:00
Mr Chen 055d440484 up 2024-01-04 19:54:50 +08:00
Mr Chen 97e2d131b4 update 2024-01-01 19:26:19 +08:00
Mr Chen e2784d2d55 Update .gitignore 2024-01-01 02:18:10 +08:00
Mr Chen 6b697ae3be Update opcache.sh 2023-12-31 02:15:07 +08:00
Mr Chen 207fa1d15e Update index.py 2023-12-30 19:58:54 +08:00
Mr Chen 454e399d3d Update phpmongoadmin.conf 2023-12-30 19:32:39 +08:00
Mr Chen 6ea8f20a9d php mongo admin 2023-12-30 19:32:17 +08:00
Mr Chen 9dc3496c27 update 2023-12-30 04:30:21 +08:00
Mr Chen b523b84609 Update info.json 2023-12-30 04:19:03 +08:00
Mr Chen e443b88ad9 phpredisadmin 2023-12-30 04:12:15 +08:00
Mr Chen 480ae78579 Update redis.conf 2023-12-30 03:32:23 +08:00
Mr Chen fb31e3ca15 Update index.py 2023-12-30 03:31:39 +08:00
Mr Chen 53fdaed5c3 Update install.sh 2023-12-30 03:21:20 +08:00
Mr Chen 37f6f2b6bc update 2023-12-30 03:21:13 +08:00
Mr Chen d1028bcc41 Update install.sh 2023-12-30 02:43:43 +08:00
Mr Chen 72e7800b50 AD调整 2023-12-30 00:04:39 +08:00
Mr Chen bb717d2963 update 2023-12-28 19:07:05 +08:00
Mr Chen 16787aebd0 Update stats.js 2023-12-28 03:34:53 +08:00
Mr Chen d769822731 Update stats.js 2023-12-28 03:32:48 +08:00
Mr Chen b6073ba8d3 Update maccms.conf 2023-12-28 00:47:18 +08:00
Mr Chen 8d50f75f18 php 升级 2023-12-27 20:46:10 +08:00
Mr Chen 8077b4cb13 Update gtid.cnf 2023-12-25 19:58:20 +08:00
Mr Chen 7a9f1ebf5e Create orm.py 2023-12-25 19:56:48 +08:00
Mr Chen 21f5670a85 Update index.py 2023-12-23 00:41:00 +08:00
Mr Chen dbd0664c72 Merge pull request #519 from midoks/dev
mysql-apt/mysql-yum 功能增强
2023-12-22 23:25:00 +08:00
Mr Chen f9e53164d9 Update README.md 2023-12-22 23:23:24 +08:00
Mr Chen 62e0321126 Update index.py 2023-12-22 23:10:47 +08:00
Mr Chen 51b82ecbbb Update index.py 2023-12-22 23:09:32 +08:00
Mr Chen 0229f50fef Update install.sh 2023-12-22 23:04:53 +08:00
Mr Chen be176001ea Update index.py 2023-12-22 22:50:33 +08:00
Mr Chen 3bea21bb94 update 2023-12-22 22:48:14 +08:00
Mr Chen 4b3104c849 Update index.py 2023-12-22 22:32:59 +08:00
Mr Chen 0cbb1ad02e Update index.py 2023-12-22 22:28:50 +08:00
Mr Chen 221f114dd4 Update index.py 2023-12-22 22:28:17 +08:00
Mr Chen 5a5c2f3e33 update 2023-12-22 22:20:03 +08:00
Mr Chen 69de62f8c3 Update index.py 2023-12-22 22:12:41 +08:00
Mr Chen af7698e157 update 2023-12-22 22:02:46 +08:00
Mr Chen f0af84f940 Update index.py 2023-12-22 21:54:05 +08:00
Mr Chen 4802dde50a update 2023-12-22 21:52:31 +08:00
Mr Chen fcbf7be2b6 update 2023-12-22 21:45:06 +08:00
Mr Chen f77484df84 update 2023-12-22 21:42:06 +08:00
Mr Chen 64ccba7595 Update index.py 2023-12-22 21:37:57 +08:00
Mr Chen b1935372a1 Update index.py 2023-12-22 21:37:37 +08:00
Mr Chen 03c9afed4a Create index_mysql_apt.py 2023-12-22 21:35:09 +08:00
Mr Chen 4e63c82e93 update 2023-12-22 21:32:20 +08:00
Mr Chen 6fa2fde791 Update index_mysql_apt.py 2023-12-22 21:23:28 +08:00
Mr Chen 98353df1ee Update index.py 2023-12-22 21:20:26 +08:00
Mr Chen 50978741aa Update index.py 2023-12-22 21:14:59 +08:00
Mr Chen d4431f11be Update index.py 2023-12-22 21:09:08 +08:00
Mr Chen 3faad62dd8 update 2023-12-22 20:58:23 +08:00
Mr Chen 6d2550e607 update 2023-12-22 20:31:23 +08:00
Mr Chen f835e4d6a1 Merge branch 'master' into dev 2023-12-22 15:53:37 +08:00
Mr Chen e33bdc5b7d Merge pull request #518 from midoks/dev
mariadb功能增强
2023-12-22 15:33:30 +08:00
Mr Chen 1e6fe01819 Update index.py 2023-12-22 15:21:12 +08:00
Mr Chen c522738df5 Update mysql.js 2023-12-22 15:20:37 +08:00
Mr Chen 5a8be9de7c Update mariadb.js 2023-12-22 15:19:44 +08:00
Mr Chen fd9c860d9b Update index.py 2023-12-22 15:11:12 +08:00
Mr Chen 306a6d450f Update index.py 2023-12-22 15:04:56 +08:00
Mr Chen 79fd1d7157 Update install.sh 2023-12-22 14:55:58 +08:00
Mr Chen 9276e811c2 update 2023-12-22 14:50:50 +08:00
Mr Chen d1493ca13f Update index.py 2023-12-22 05:27:01 +08:00
Mr Chen 13c605d58a Update index.py 2023-12-22 05:26:16 +08:00
Mr Chen 36d19f2250 up 2023-12-22 05:21:59 +08:00
Mr Chen 8f229c99be Update index.py 2023-12-22 05:05:48 +08:00
Mr Chen 72b16e9540 update 2023-12-22 04:59:19 +08:00
Mr Chen dbe2a1f0df Update index.py 2023-12-22 04:56:05 +08:00
Mr Chen 4c3f8c095f Update index.py 2023-12-22 04:55:30 +08:00
Mr Chen 589933dc33 Update index.py 2023-12-22 04:53:05 +08:00
Mr Chen de36f41182 Update index.py 2023-12-22 04:51:07 +08:00
Mr Chen 8e1b4881c4 Update index.py 2023-12-22 04:22:10 +08:00
Mr Chen 692872ecd6 Update index.py 2023-12-22 04:14:58 +08:00
Mr Chen d422a640d5 Update index.py 2023-12-22 03:48:35 +08:00
Mr Chen 46d293613e Update index.py 2023-12-22 03:46:26 +08:00
Mr Chen b775625890 Update index.py 2023-12-22 03:25:54 +08:00
Mr Chen eb2bb595de Update index.py 2023-12-22 03:10:31 +08:00
Mr Chen 0ddc3bf762 Update index.py 2023-12-22 03:05:50 +08:00
Mr Chen e45604f211 update 2023-12-22 02:49:13 +08:00
Mr Chen 4f22d9ae70 update 2023-12-22 02:39:43 +08:00
Mr Chen 732363ec41 Update index.py 2023-12-22 01:26:16 +08:00
Mr Chen bc688aa93f update 2023-12-22 01:23:47 +08:00
Mr Chen 56ed68b888 mariadb 二进制查看 2023-12-22 01:17:45 +08:00
Mr Chen 90539a5049 Update index.py 2023-12-22 01:08:36 +08:00
Mr Chen df15100272 Update mariadb.js 2023-12-22 01:04:20 +08:00
Mr Chen 4bfec3ac06 Update index.py 2023-12-22 01:01:46 +08:00
Mr Chen 3a80a27970 Update mysql.js 2023-12-22 00:56:02 +08:00
Mr Chen 09e79aff63 Update index.py 2023-12-22 00:55:18 +08:00
Mr Chen 41a36a6fd3 Update index.py 2023-12-22 00:52:15 +08:00
Mr Chen fc0974dc91 mysql修复功能-敏感功能优化 2023-12-22 00:34:23 +08:00
Mr Chen 4942c92b33 Update index.py 2023-12-22 00:24:08 +08:00
Mr Chen e173c2e51a mysql修复功能-敏感功能优化 2023-12-22 00:18:41 +08:00
Mr Chen daddf317e2 Update info.json 2023-12-21 19:07:32 +08:00
Mr Chen 7e919050b2 Create my8.2.cnf 2023-12-21 19:01:03 +08:00
Mr Chen af9d050536 update 2023-12-21 18:59:32 +08:00
Mr Chen a9e6acd407 Update phplib.conf 2023-12-21 18:57:03 +08:00
Mr Chen 180e67dde9 Update info.json 2023-12-21 18:11:37 +08:00
Mr Chen f8451fadba Create install.sh 2023-12-21 18:10:49 +08:00
Mr Chen 558bfcb1ee 调整 2023-12-20 01:15:06 +08:00
Mr Chen 6a27e69ee7 Update config_api.py 2023-12-19 23:34:11 +08:00
Mr Chen b5d28b4ef2 流量显示优化 2023-12-19 23:31:18 +08:00
Mr Chen 8f80336901 Update index.py 2023-12-18 22:18:54 +08:00
Mr Chen 0a78dda06c update 2023-12-18 22:13:03 +08:00
Mr Chen b6c3020705 Update index.py 2023-12-18 21:42:56 +08:00
Mr Chen ed70d4faa3 Update index.py 2023-12-18 21:41:26 +08:00
Mr Chen 46e4f55105 Merge pull request #517 from midoks/dev
mongodb优化
2023-12-17 13:52:23 +08:00
Mr Chen 235f0b6d66 Update mongodb.conf 2023-12-17 13:47:30 +08:00
Mr Chen 633066088d Update index.py 2023-12-17 13:32:39 +08:00
Mr Chen 48f223f4f9 Update index.html 2023-12-16 20:59:29 +08:00
Mr Chen 709a91dcec Update mongodb.js 2023-12-16 17:06:22 +08:00
Mr Chen 2592291b49 update 2023-12-16 17:01:49 +08:00
Mr Chen 502893194e mongo状态 2023-12-16 16:30:34 +08:00
Mr Chen 8976e97ea5 Update mongodb.conf 2023-12-16 15:25:18 +08:00
Mr Chen 22cb5f3bc2 Update config.js 2023-12-15 18:36:20 +08:00
Mr Chen 0888b89ea7 Update config.js 2023-12-15 18:36:14 +08:00
Mr Chen 738e69562e Update config.js 2023-12-15 18:35:54 +08:00
Mr Chen 511b62d911 Merge pull request #516 from midoks/dev
mysql8.2及密码生成加强
2023-12-15 14:49:43 +08:00
Mr Chen d748674b49 Update public.js 2023-12-15 14:48:54 +08:00
Mr Chen 828372f16f Update public.js 2023-12-15 14:47:52 +08:00
Mr Chen a349b2bc81 Update install.sh 2023-12-14 14:00:31 +08:00
Mr Chen 4f3fe2af54 Update index.py 2023-12-14 13:59:08 +08:00
Mr Chen 4670811fd6 Create my8.2.cnf 2023-12-14 13:33:04 +08:00
Mr Chen e1fb85859a Update install.sh 2023-12-14 01:01:21 +08:00
Mr Chen c0fc1148eb Update install.sh 2023-12-14 01:01:01 +08:00
Mr Chen 50052e7650 Update install.sh 2023-12-14 00:58:02 +08:00
Mr Chen 8053f9b593 Update install.sh 2023-12-14 00:30:58 +08:00
Mr Chen 1a5cdca70d Update mysql.js 2023-12-14 00:22:27 +08:00
Mr Chen 341690d234 Update mysql.js 2023-12-14 00:20:24 +08:00
Mr Chen d76654b853 Update mysql.js 2023-12-14 00:17:37 +08:00
Mr Chen 0ef35e1474 Update mysql.js 2023-12-14 00:12:56 +08:00
Mr Chen 9ea52e452a mysql识别登录加密规则 2023-12-14 00:04:48 +08:00
Mr Chen 5e39e1a463 Update my8.0.cnf 2023-12-13 23:54:39 +08:00
Mr Chen 36421ae254 update 2023-12-13 23:51:18 +08:00
Mr Chen a34f025a36 Update index.py 2023-12-13 23:33:25 +08:00
Mr Chen 7be4f9ea98 Update index.py 2023-12-13 23:32:59 +08:00
Mr Chen 2dc93bf490 Update my8.0.cnf 2023-12-13 23:27:18 +08:00
Mr Chen 73fb46fcc0 Merge pull request #515 from midoks/dev
mongodb配置优化
2023-12-12 14:54:49 +08:00
Mr Chen f4ea1dc544 Update index.py 2023-12-12 14:51:47 +08:00
Mr Chen d17cc990fe Update index.py 2023-12-12 14:44:39 +08:00
Mr Chen 8edd40393b Update index.py 2023-12-12 14:44:23 +08:00
Mr Chen 98e653710c Update index.py 2023-12-12 14:43:49 +08:00
Mr Chen 3eb6937778 Update layout.html 2023-12-12 13:22:31 +08:00
Mr Chen 974eaf3583 Merge branch 'master' into dev 2023-12-11 23:32:27 +08:00
Mr Chen dadcc2df6d Merge pull request #514 from midoks/dev
部分更新
2023-12-11 23:32:14 +08:00
Mr Chen 639d5413e5 up 2023-12-11 23:20:34 +08:00
Mr Chen 1d114d9db7 Update cmd.md 2023-12-09 15:59:36 +08:00
Mr Chen dfa669a032 Update cmd.md 2023-12-09 15:58:57 +08:00
Mr Chen bf370685b3 Update install.sh 2023-12-07 13:27:46 +08:00
Mr Chen 8f9bdde0a1 Update info.json 2023-12-06 21:10:32 +08:00
Mr Chen dbbc32258a Create install.sh 2023-12-06 21:09:56 +08:00
Mr Chen bf79e3028a Merge pull request #513 from midoks/dev
地址更新
2023-12-05 13:08:47 +08:00
Mr Chen 0650858824 update 2023-12-05 13:07:56 +08:00
Mr Chen 83f736d5b2 Update install.sh 2023-12-05 13:06:59 +08:00
Mr Chen bafee3782a Merge pull request #512 from midoks/dev
地址更新
2023-12-04 16:24:36 +08:00
Mr Chen 1aff003ba3 Update mw.tpl 2023-12-04 16:23:54 +08:00
Mr Chen 30e779686a Merge pull request #511 from midoks/dev
域名更改
2023-12-04 13:19:24 +08:00
Mr Chen 15eccc72f3 Update README.md 2023-12-04 13:18:46 +08:00
Mr Chen f69691fac7 Update plugins_api.py 2023-12-04 00:13:41 +08:00
Mr Chen 1ffcb9ca7d 站点-优化提示 2023-12-04 00:10:03 +08:00
Mr Chen 75514f8e5c update 2023-12-03 03:15:13 +08:00
Mr Chen 098be84816 Update push_bbs_ntid.py 2023-12-03 03:14:19 +08:00
Mr Chen 8752e394a3 Update mw.py 2023-12-03 01:23:18 +08:00
Mr Chen 0350f3ecbb Update mw.py 2023-12-03 01:17:50 +08:00
Mr Chen 3c855afc43 Merge pull request #510 from midoks/dev
简单更新
2023-12-03 00:31:34 +08:00
Mr Chen 0c8ec2132f Update README.md 2023-12-03 00:30:43 +08:00
Mr Chen e3deac06b4 Update README.md 2023-12-03 00:30:09 +08:00
Mr Chen b92dbea2c8 update 2023-12-01 12:09:20 +08:00
Mr Chen 4da6738909 Merge pull request #509 from midoks/dev
换自建域名
2023-12-01 11:44:12 +08:00
Mr Chen 1665256627 换自建域名 2023-12-01 11:43:31 +08:00
Mr Chen d49ebe9fa8 Update index.py 2023-11-29 00:35:51 +08:00
Mr Chen 6dbdf26d80 Update index.py 2023-11-28 17:33:02 +08:00
Mr Chen 114ed15c02 Update supervisor.service 2023-11-28 12:49:56 +08:00
Mr Chen 315eb82a89 Update index.py 2023-11-28 12:46:23 +08:00
Mr Chen f4ef03304d Update install.sh 2023-11-28 12:28:04 +08:00
Mr Chen 9877d04979 查看日志优化 2023-11-25 22:09:17 +08:00
Mr Chen e6f379db9d Merge pull request #507 from midoks/dev
php83正式版发布
2023-11-24 17:01:00 +08:00
Mr Chen ecad324fc6 Update install.sh 2023-11-24 16:27:45 +08:00
Mr Chen ed13ee1645 Update install.sh 2023-11-24 16:26:33 +08:00
Mr Chen 603c436f4e Update commit.tpl 2023-11-23 19:33:01 +08:00
Mr Chen d917c23fda Update webstats_common.lua 2023-11-21 22:17:01 +08:00
Mr Chen a0c4273280 Update webstats_common.lua 2023-11-21 21:59:24 +08:00
Mr Chen 8e71d0a306 Update webstats_common.lua 2023-11-21 19:08:39 +08:00
Mr Chen 01dfb6f248 Merge pull request #506 from midoks/dev
命令行开启ipv6支持
2023-11-21 00:44:34 +08:00
Mr Chen 4ab1d14ffe update 2023-11-21 00:43:38 +08:00
Mr Chen 665fe41014 Update tool_migrate.py 2023-11-20 23:51:12 +08:00
Mr Chen ddba4f3abe Update tool_migrate.py 2023-11-20 23:43:18 +08:00
Mr Chen 1f65f80bef Update webstats_common.lua 2023-11-20 23:40:07 +08:00
Mr Chen 8dd9f707a6 命令行开启ip支持 2023-11-20 20:57:53 +08:00
Mr Chen 14437611c8 Merge pull request #505 from midoks/dev
增加php扩展
2023-11-20 01:01:13 +08:00
Mr Chen bfe857ee59 Update install.sh 2023-11-19 22:00:53 +08:00
Mr Chen 01efa67bf1 Merge branch 'master' of https://github.com/midoks/mdserver-web 2023-11-19 21:38:07 +08:00
Mr Chen 3b3356d5c6 update 2023-11-19 21:37:41 +08:00
Mr Chen 6dbfd385fb Update readline.sh 2023-11-19 21:34:35 +08:00
Mr Chen 1e9fa587f5 Update all_test.sh 2023-11-19 21:34:30 +08:00
Mr Chen fd673b76e8 Update phplib.conf 2023-11-19 21:34:07 +08:00
Mr Chen d2340872c0 Update libedit.sh 2023-11-19 21:05:46 +08:00
Mr Chen 1c14566b6c Update readline.sh 2023-11-19 21:03:49 +08:00
Mr Chen adde0086aa Create libedit.sh 2023-11-19 21:02:31 +08:00
Mr Chen b6ca99f1ef Update libiconv.sh 2023-11-19 20:50:16 +08:00
Mr Chen c920b46a13 Update readline.sh 2023-11-19 20:37:30 +08:00
Mr Chen 338e64d295 Update event.sh 2023-11-19 20:34:08 +08:00
Mr Chen f030f7a97d event 2023-11-19 20:33:19 +08:00
Mr Chen ef7da2ec96 update 2023-11-19 20:30:47 +08:00
Mr Chen 6dec09741f Update maccms.conf 2023-11-19 19:26:03 +08:00
Mr Chen 6d75a65a09 Update maccms.conf 2023-11-19 17:38:23 +08:00
Mr Chen 8eeb55d555 Update maccms.conf 2023-11-19 17:32:53 +08:00
Mr Chen f54feaa87b Update maccms.conf 2023-11-19 17:29:50 +08:00
Mr Chen b828fc2188 Update maccms.conf 2023-11-19 17:23:22 +08:00
Mr Chen e645be4285 Update maccms.conf 2023-11-19 17:18:01 +08:00
Mr Chen 05a7b8818e Update maccms.conf 2023-11-19 17:10:53 +08:00
Mr Chen 391b313a65 Update maccms.conf 2023-11-19 17:06:13 +08:00
Mr Chen df7bff4a72 Update maccms.conf 2023-11-19 17:04:10 +08:00
Mr Chen 2eefd7d3fa Update maccms.conf 2023-11-19 16:58:15 +08:00
Mr Chen 130e4cf546 Update maccms.conf 2023-11-19 16:55:05 +08:00
Mr Chen 096dfa6b96 Create maccms.conf 2023-11-19 16:54:36 +08:00
Mr Chen 77361259c3 Update install.sh 2023-11-19 16:10:22 +08:00
Mr Chen 4aad9f90db mac 不判断root 2023-11-08 11:58:50 +08:00
175 changed files with 8719 additions and 901 deletions
+2 -2
View File
@@ -154,6 +154,7 @@ data/notify.json
data/api.json
data/bind_domain.pl
data/unauthorized_status.pl
data/auth_secret.pl
plugins/vip_*
plugins/own_*
@@ -171,10 +172,9 @@ plugins/fastdfs
plugins/v2ray
plugins/frp
plugins/file_search
plugins/proxysql
debug.out
mdioks.session-journal
*.session
+15 -23
View File
@@ -29,20 +29,20 @@
基本上可以使用,后续会继续优化!欢迎提供意见!
- 吹水组 - https://t.me/mdserver_web
- 交流论坛 - https://bbs.midoks.me
- 交流论坛 - https://bbs.midoks.icu
- discord - https://discord.gg/3zXk4mES
```
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
Talk is cheap, show me the code. -- linus
```
- [兼容性测试报告](/compatibility.md)
- [常用命令说明](/cmd.md)
- [常用命令说明](/cmd.md) [ mw default ]
### 主要插件介绍
* OpenResty - 轻量级,占有内存少,并发能力强。
* PHP[53-82] - PHP是世界上最好的编程语言。
* PHP[53-83] - PHP是世界上最好的编程语言。
* MySQL - 一种关系数据库管理系统。
* MariaDB - 是MySQL的一个重要分支。
* MySQL[APT/YUM] - 一种关系数据库管理系统。
@@ -78,7 +78,7 @@ phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
phpMyAdmin[5.2.0]支持MySQL[8.0]
PHP[53-72]支持phpMyAdmin[4.4.15]
PHP[72-82]支持phpMyAdmin[5.2.0]
PHP[72-83]支持phpMyAdmin[5.2.0]
```
# 郑重声明
@@ -90,7 +90,7 @@ PHP[72-82]支持phpMyAdmin[5.2.0]
# 特别赞助
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan1.cc)
# AD - VPS推荐 - 🙏
@@ -102,26 +102,18 @@ PHP[72-82]支持phpMyAdmin[5.2.0]
# Docker
- 由[DDSRem](https://github.com/DDSRem)开发维护。
- https://hub.docker.com/r/ddsderek/mw
- 由[DDS-Derek](https://github.com/DDS-Derek)开发维护。
- https://github.com/DDS-Derek/mdserver-web-Docker
```
docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:443 -p 888:888 ddsderek/mw-server:latest
```
### 版本更新 0.16.2
### 版本更新 0.16.4
* keepalived插件改造,集成mysql高可用配置。
* redis(主从/集群)配置识别。
* MySQL主从同步1236错误,添加修复功能。
* MySQL二进制日志查看。
* 源码安装成功后删除解压包,节省体积。
* 网站统计-增加查询条件。
* php增加yaml扩展。
* php扩展ioncube修复。
* php-fpm增加【按需】配置。
* gitea/gogs同步功能改造。
* 二次验证。
* OP防火墙修复。
### JSDelivr安装地址
@@ -149,7 +141,7 @@ wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/m
```
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/master/scripts/install.sh | bash
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/master/scripts/install.sh | bash
```
- 直接更新
@@ -186,8 +178,8 @@ wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/mi
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
```
### 捐赠地址 USDT(TRC20)
@@ -199,7 +191,7 @@ TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
### 微信赞助
[![截图](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)
[![截图](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/alipay_zz.jpg)](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/alipay_zz.jpg)
### 无图不真相
+1 -12
View File
@@ -33,10 +33,10 @@ from flask import redirect
def init():
initDB()
initDBSshPort()
initUserInfo()
initInitD()
initInitTask()
return True
def local():
@@ -63,17 +63,6 @@ def initDB():
print(str(ex))
def initDBSshPort():
# SSH端口必须放开
import firewall_api
cmd_data = mw.execShell(
"cat /etc/ssh/sshd_config | grep '^Port \d*' | tail -1")
ssh_port = cmd_data[0].replace("Port ", '').strip()
if ssh_port == '':
ssh_port = '22'
firewall_api.firewall_api().addAcceptPortArgs(ssh_port, 'SSH远程管理服务', 'port')
def doContentReplace(src, dst):
content = mw.readFile(src)
content = content.replace("{$SERVER_PATH}", mw.getRunDir())
+121 -47
View File
@@ -20,6 +20,7 @@ import mw
import re
import json
import pwd
import pytz
from flask import session
from flask import request
@@ -27,9 +28,26 @@ from flask import request
class config_api:
__version = '0.16.2'
__version = '0.16.4'
__api_addr = 'data/api.json'
# 统一默认配置文件
__file = {
'api' : 'data/api.json', # API文件
'debug' : 'data/debug.pl', # DEBUG文件
'close' : 'data/close.pl', # 识别关闭面板文件
'basic_auth' : 'data/basic_auth.json', # 面板Basic验证
'admin_path' : 'data/admin_path.pl', # 面板后缀路径设置
'ipv6' : 'data/ipv6.pl', # ipv6识别文件
'bind_domain' : 'data/bind_domain.pl', # 面板域名绑定
'unauth_status' : 'data/unauthorized_status.pl', # URL路径未成功显示状态
'auth_secret': 'data/auth_secret.pl', # 二次验证密钥
'ssl':'data/ssl.pl', # ssl设置
'hook_database' : 'data/hook_database.json', # 数据库钩子
'hook_menu' : 'data/hook_menu.json', # 菜单钩子
'hook_global_static' : 'data/hook_global_static.json', # 静态文件钩子
}
def __init__(self):
pass
@@ -178,7 +196,7 @@ class config_api:
basic_open = request.form.get('is_open', '').strip()
salt = '_md_salt'
path = 'data/basic_auth.json'
path = self.__file['basic_auth']
is_open = True
if basic_open == 'false':
@@ -223,7 +241,7 @@ class config_api:
backup_path = request.form.get('backup_path', '')
if domain != '':
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
reg = "^([\\w\\-\\*]{1,100}\\.){1,4}(\\w{1,10}|\\w{1,10}\\.\\w{1,10})$"
if not re.match(reg, domain):
return mw.returnJson(False, '主域名格式不正确')
@@ -285,7 +303,7 @@ class config_api:
return mw.returnJson(False, '安全入口地址长度不能小于6位!')
if admin_path in admin_path_checks:
return mw.returnJson(False, '该入口已被面板占用,请使用其它入口!')
if not re.match("^/[\w\./-_]+$", admin_path):
if not re.match("^/[\\w\\./-_]+$", admin_path):
return mw.returnJson(False, '入口地址格式不正确,示例: /mw_rand')
# else:
# domain = mw.readFile('data/bind_domain.pl')
@@ -299,7 +317,7 @@ class config_api:
# '警告,关闭安全入口等于直接暴露你的后台地址在外网,十分危险,至少开启以下一种安全方式才能关闭:<a
# style="color:red;"><br>1、绑定访问域名<br>2、绑定授权IP</a>')
admin_path_file = 'data/admin_path.pl'
admin_path_file = self.__file['admin_path']
admin_path_old = '/'
if os.path.exists(admin_path_file):
admin_path_old = mw.readFile(admin_path_file).strip()
@@ -310,7 +328,7 @@ class config_api:
return mw.returnJson(True, '修改成功!')
def closePanelApi(self):
filename = 'data/close.pl'
filename = self.__file['close']
if os.path.exists(filename):
os.remove(filename)
return mw.returnJson(True, '开启成功')
@@ -328,8 +346,8 @@ class config_api:
return mw.returnJson(True, '开发模式开启!')
def setIpv6StatusApi(self):
ipv6_file = 'data/ipv6.pl'
if os.path.exists('data/ipv6.pl'):
ipv6_file = self.__file['ipv6']
if os.path.exists(ipv6_file):
os.remove(ipv6_file)
mw.writeLog('面板设置', '关闭面板IPv6兼容!')
else:
@@ -399,7 +417,7 @@ class config_api:
# 设置面板SSL证书设置
def setPanelHttpToHttpsApi(self):
bind_domain = 'data/bind_domain.pl'
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
@@ -429,9 +447,9 @@ class config_api:
else:
conf = mw.readFile(panel_ssl)
if conf:
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
conf = re.sub(rep, '', conf)
mw.writeFile(panel_ssl, conf)
@@ -444,7 +462,7 @@ class config_api:
# 删除面板证书
def delPanelSslApi(self):
bind_domain = 'data/bind_domain.pl'
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
@@ -473,7 +491,7 @@ class config_api:
def applyPanelLetSslApi(self):
# check domain is bind?
bind_domain = 'data/bind_domain.pl'
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
@@ -530,7 +548,7 @@ class config_api:
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
cfg_domain = 'data/bind_domain.pl'
cfg_domain = self.__file['bind_domain']
if domain == '':
os.remove(cfg_domain)
os.remove(dst_panel_path)
@@ -559,7 +577,7 @@ class config_api:
# 设置面板SSL
def setPanelSslApi(self):
sslConf = mw.getRunDir() + '/data/ssl.pl'
sslConf = mw.getRunDir() + '/' + self.__file['ssl']
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
@@ -568,35 +586,35 @@ class config_api:
conf = mw.readFile(dst_panel_path)
if conf:
rep = "\s+ssl_certificate\s+.+;\s+ssl_certificate_key\s+.+;"
rep = "\\s+ssl_certificate\\s+.+;\\s+ssl_certificate_key\\s+.+;"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_protocols\s+.+;\n"
rep = "\\s+ssl_protocols\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ciphers\s+.+;\n"
rep = "\\s+ssl_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_prefer_server_ciphers\s+.+;\n"
rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_cache\s+.+;\n"
rep = "\\s+ssl_session_cache\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_timeout\s+.+;\n"
rep = "\\s+ssl_session_timeout\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ecdh_curve\s+.+;\n"
rep = "\\s+ssl_ecdh_curve\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_tickets\s+.+;\n"
rep = "\\s+ssl_session_tickets\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling\s+.+;\n"
rep = "\\s+ssl_stapling\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling_verify\s+.+;\n"
rep = "\\s+ssl_stapling_verify\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl\s+on;"
rep = "\\s+ssl\\s+on;"
conf = re.sub(rep, '', conf)
rep = "\s+error_page\s497.+;"
rep = "\\s+error_page\\s497.+;"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+443.*;"
rep = "\\s+listen\\s+443.*;"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+\[\:\:\]\:443.*;"
rep = "\\s+listen\\s+\\[\\:\\:\\]\\:443.*;"
conf = re.sub(rep, '', conf)
mw.writeFile(dst_panel_path, conf)
@@ -627,7 +645,7 @@ class config_api:
conf = conf.replace('#error_page 404/404.html;', sslStr)
rep = "listen\s+([0-9]+)\s*[default_server]*;"
rep = "listen\\s+([0-9]+)\\s*[default_server]*;"
tmp = re.findall(rep, conf)
if not mw.inArray(tmp, '443'):
listen = re.search(rep, conf).group()
@@ -743,15 +761,15 @@ class config_api:
def setStatusCodeApi(self):
status_code = request.form.get('status_code', '').strip()
if re.match("^\d+$", status_code):
if re.match("^\\d+$", status_code):
status_code = int(status_code)
if status_code != 0:
if status_code < 100 or status_code > 999:
return mw.returnJson(False, '状态码范围错误!')
else:
return mw.returnJson(False, '状态码范围错误!')
mw.writeFile('data/unauthorized_status.pl', str(status_code))
unauthorized_status = self.__file['unauth_status']
mw.writeFile(unauthorized_status, str(status_code))
mw.writeLog('面板设置', '将未授权响应状态码设置为:{}'.format(status_code))
return mw.returnJson(True, '设置成功!')
@@ -870,8 +888,7 @@ class config_api:
if not 'token_crypt' in data:
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
data['token_crypt'] = mw.enCrypt(
data['token'], token).decode('utf-8')
data['token_crypt'] = mw.enCrypt(data['token'], token).decode('utf-8')
token = stats[data['open']] + '成功!'
mw.writeLog('API配置', '%sAPI接口' % stats[data['open']])
@@ -887,7 +904,7 @@ class config_api:
return mw.returnJson(True, '保存成功!')
def renderUnauthorizedStatus(self, data):
cfg_unauth_status = 'data/unauthorized_status.pl'
cfg_unauth_status = self.__file['unauth_status']
if os.path.exists(cfg_unauth_status):
status_code = mw.readFile(cfg_unauth_status)
data['status_code'] = status_code
@@ -911,6 +928,52 @@ class config_api:
data['status_code_msg'] = "默认-安全入口错误提示"
return data
def getTimezoneListApi(self):
# 获取时区列表
# pytz.all_timezones | 所有
# pytz.common_timezones
return pytz.all_timezones
def setTimezoneApi(self):
# 设置时区列表
timezone = request.form.get('timezone', '').strip()
cmd = 'timedatectl set-timezone "'+timezone+'"'
mw.execShell(cmd)
return mw.returnJson(True, '设置成功!')
def getAuthSecretApi(self):
reset = request.form.get('reset', '')
import pyotp
auth = self.__file['auth_secret']
tag = 'mdserver-web'
if os.path.exists(auth) and reset != '1':
content = mw.readFile(auth)
sec = mw.deDoubleCrypt(tag,content)
else:
sec = pyotp.random_base32()
crypt_data = mw.enDoubleCrypt(tag, sec)
mw.writeFile(auth, crypt_data)
ip = mw.getHostAddr()
url = pyotp.totp.TOTP(sec).provisioning_uri(name=ip, issuer_name='mdserver-web')
rdata = {}
rdata['secret'] = sec
rdata['url'] = url
return mw.returnJson(True, '设置成功!', rdata)
def setAuthSecretApi(self):
auth = self.__file['auth_secret']
if os.path.exists(auth):
os.remove(auth)
return mw.returnJson(True, '关闭成功!', 0)
else:
return mw.returnJson(True, '开启成功!', 1)
def get(self):
data = {}
@@ -923,31 +986,38 @@ class config_api:
data['port'] = mw.getHostPort()
data['ip'] = mw.getHostAddr()
admin_path_file = 'data/admin_path.pl'
admin_path_file = self.__file['admin_path']
if not os.path.exists(admin_path_file):
data['admin_path'] = '/'
else:
data['admin_path'] = mw.readFile(admin_path_file)
ipv6_file = 'data/ipv6.pl'
ipv6_file = self.__file['ipv6']
if os.path.exists(ipv6_file):
data['ipv6'] = 'checked'
else:
data['ipv6'] = ''
debug_file = 'data/debug.pl'
debug_file = self.__file['debug']
if os.path.exists(debug_file):
data['debug'] = 'checked'
else:
data['debug'] = ''
ssl_file = 'data/ssl.pl'
if os.path.exists('data/ssl.pl'):
ssl_file = self.__file['ssl']
if os.path.exists(ssl_file):
data['ssl'] = 'checked'
else:
data['ssl'] = ''
basic_auth = 'data/basic_auth.json'
auth_secret = self.__file['auth_secret']
if os.path.exists(auth_secret):
data['auth_secret'] = 'checked'
else:
data['auth_secret'] = ''
basic_auth = self.__file['basic_auth']
if os.path.exists(basic_auth):
bac = mw.readFile(basic_auth)
bac = json.loads(bac)
@@ -956,7 +1026,7 @@ class config_api:
else:
data['basic_auth'] = ''
cfg_domain = 'data/bind_domain.pl'
cfg_domain = self.__file['bind_domain']
if os.path.exists(cfg_domain):
domain = mw.readFile(cfg_domain)
data['bind_domain'] = domain.strip()
@@ -965,6 +1035,7 @@ class config_api:
data = self.renderUnauthorizedStatus(data)
#api
api_token = self.__api_addr
if os.path.exists(api_token):
bac = mw.readFile(api_token)
@@ -974,6 +1045,9 @@ class config_api:
else:
data['api_token'] = ''
#auth
data['site_count'] = mw.M('sites').count()
data['username'] = mw.M('users').where(
@@ -982,7 +1056,7 @@ class config_api:
data['hook_tag'] = request.args.get('tag', '')
# databases hook
database_hook_file = 'data/hook_database.json'
database_hook_file = self.__file['hook_database']
if os.path.exists(database_hook_file):
df = mw.readFile(database_hook_file)
df = json.loads(df)
@@ -991,7 +1065,7 @@ class config_api:
data['hook_database'] = []
# menu hook
menu_hook_file = 'data/hook_menu.json'
menu_hook_file = self.__file['hook_menu']
if os.path.exists(menu_hook_file):
df = mw.readFile(menu_hook_file)
df = json.loads(df)
@@ -1000,7 +1074,7 @@ class config_api:
data['hook_menu'] = []
# global_static hook
global_static_hook_file = 'data/hook_global_static.json'
global_static_hook_file = self.__file['hook_global_static']
if os.path.exists(global_static_hook_file):
df = mw.readFile(global_static_hook_file)
df = json.loads(df)
+3 -1
View File
@@ -77,7 +77,9 @@ class logs_api:
if log_name in ['dmesg'] or log_name.find('dmesg') == 0:
return '内核缓冲区日志'
if log_name in ['syslog'] or log_name.find('syslog') == 0:
return '系统警告/错误日志'
return '系统日志'
if log_name in ['rsyncd.log']:
return '远程同步日志'
if log_name in ['btmp']:
return '失败的登录记录'
if log_name in ['utmp', 'wtmp']:
+25 -7
View File
@@ -246,7 +246,7 @@ def isInstalledWeb():
def isIpAddr(ip):
check_ip = re.compile(
'^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$')
'^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$')
if check_ip.match(ip):
return True
else:
@@ -394,6 +394,9 @@ def getPageObject(args, result='1,2,3,4,5,8'):
if 'tojs' in args:
info['return_js'] = args['tojs']
if 'args_tpl' in args:
info['args_tpl'] = args['args_tpl']
return (page.GetPage(info, result), page)
@@ -905,7 +908,22 @@ def aesDecrypt_Crypto(data, key, vi):
text_decrypted = text_decrypted.decode('utf8').rstrip() # 去掉补位的右侧空格
return text_decrypted
def encodeImage(imgsrc, newsrc):
# 图片加密
import struct
old_fp = open(imgsrc, 'rb')
imgFile = old_fp.read()
old_fp.close()
new_fp = open(newsrc,"wb")
for x in imgFile:
value = x ^ 86
value = hex(value)
s = struct.pack('B',int(value,16))
new_fp.write(s)
new_fp.close()
return True
def buildSoftLink(src, dst, force=False):
'''
建立软连接
@@ -1158,10 +1176,10 @@ def getLocalIpBack():
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
req = urllib.request.urlopen(url, timeout=10)
content = req.read().decode('utf-8')
ipaddress = re.search('\d+.\d+.\d+.\d+', content).group(0)
ipaddress = re.search('\\d+.\\d+.\\d+.\\d+', content).group(0)
writeFile(filename, ipaddress)
ipaddress = re.search('\d+.\d+.\d+.\d+', ipaddress).group(0)
ipaddress = re.search('\\d+.\\d+.\\d+.\\d+', ipaddress).group(0)
return ipaddress
except Exception as ex:
# print(ex)
@@ -1226,7 +1244,7 @@ def checkIp(ip):
# 检查是否为IPv4地址
import re
p = re.compile(
'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
'^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$')
if p.match(ip):
return True
else:
@@ -1364,13 +1382,13 @@ def getCpuType():
# 取CPU类型
cpuinfo = open('/proc/cpuinfo', 'r').read()
rep = "model\s+name\s+:\s+(.+)"
rep = "model\\s+name\\s+:\\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
if tmp:
cpuType = tmp.groups()[0]
else:
cpuinfo = execShell('LANG="en_US.UTF-8" && lscpu')[0]
rep = "Model\s+name:\s+(.+)"
rep = "Model\\s+name:\\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
if tmp:
cpuType = tmp.groups()[0]
@@ -1754,7 +1772,7 @@ def getSSHPort():
try:
file = '/etc/ssh/sshd_config'
conf = readFile(file)
rep = "(#*)?Port\s+([0-9]+)\s*\n"
rep = "(#*)?Port\\s+([0-9]+)\\s*\n"
port = re.search(rep, conf).groups(0)[1]
return int(port)
except:
+14 -6
View File
@@ -39,6 +39,7 @@ class Page():
__RTURN_JS = False # 是否返回JS回调
__START_NUM = None # 起始行
__END_NUM = None # 结束行
__ARGS_TPL = ''
def __init__(self):
if False:
@@ -51,12 +52,19 @@ class Page():
self.__FO = tmp['FO']
self.__LINE = tmp['LINE']
def getPageNum(self, num):
return str(num) + self.__ARGS_TPL
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
# 取分页信息
# @param pageInfo 传入分页参数字典
# @param limit 返回系列
self.__RTURN_JS = pageInfo['return_js']
self.__COUNT_ROW = pageInfo['count']
if 'args_tpl' in pageInfo:
self.__ARGS_TPL = pageInfo['args_tpl']
self.ROW = pageInfo['row']
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
self.__START_NUM = self.__StartRow()
@@ -111,7 +119,7 @@ class Page():
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
else:
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
"(" + str(self.__COUNT_PAGE) + ")'>" + \
"(" + self.getPageNum(self.__COUNT_PAGE) + ")'>" + \
str(self.__END) + "</a>"
return endStr
@@ -126,7 +134,7 @@ class Page():
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
else:
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
"(" + str(self.__C_PAGE + 1) + ")'>" + \
"(" + self.getPageNum(self.__C_PAGE + 1) + ")'>" + \
str(self.__NEXT) + "</a>"
return nextStr
@@ -151,7 +159,7 @@ class Page():
"p=" + str(page) + "'>" + str(page) + "</a>"
else:
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
"(" + str(page) + ")'>" + str(page) + "</a>"
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
# 当前页
if self.__C_PAGE > 0:
@@ -174,7 +182,7 @@ class Page():
"p=" + str(page) + "'>" + str(page) + "</a>"
else:
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
"(" + str(page) + ")'>" + str(page) + "</a>"
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
return pages
@@ -189,7 +197,7 @@ class Page():
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
else:
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
"(" + str(self.__C_PAGE - 1) + ")'>" + \
"(" + self.getPageNum(self.__C_PAGE - 1) + ")'>" + \
str(self.__PREV) + "</a>"
return startStr
@@ -204,7 +212,7 @@ class Page():
self.__URI + "p=1'>" + str(self.__START) + "</a>"
else:
startStr = "<a class='Pstart' onclick='" + \
self.__RTURN_JS + "(1)'>" + str(self.__START) + "</a>"
self.__RTURN_JS + "("+self.getPageNum(1)+")'>" + str(self.__START) + "</a>"
return startStr
def __GetCpage(self, p):
+1 -1
View File
@@ -148,7 +148,7 @@ class plugins_api:
def initApi(self):
plugin_names = {
'openresty': '1.21.4.2',
'openresty': '1.21.4.3',
'php': '56',
'swap': '1.1',
'mysql': '5.7',
+30 -11
View File
@@ -105,7 +105,7 @@ class site_api:
start = (int(p) - 1) * (int(limit))
siteM = mw.M('sites').field('id,name,path,status,ps,addtime,edate')
siteM = siteC = mw.M('sites').field('id,name,path,status,ps,addtime,edate,type_id')
sql_where = ''
if search != '':
@@ -113,30 +113,37 @@ class site_api:
if type_id != '' and int(type_id) >= 0 and search != '':
sql_where = sql_where + " and type_id=" + type_id + ""
elif type_id != '' and int(type_id) >= 0:
if type_id != '' and int(type_id) >= 0:
sql_where = " type_id=" + type_id
if sql_where != '':
siteM.where(sql_where)
_list = siteM.limit((str(start)) + ',' +
limit).order('id desc').select()
_list = siteM.limit((str(start)) + ',' +limit).order('id desc').select()
if _list != None:
for i in range(len(_list)):
_list[i]['backup_count'] = mw.M('backup').where(
"pid=? AND type=?", (_list[i]['id'], 0)).count()
_list[i]['backup_count'] = mw.M('backup').where("pid=? AND type=?", (_list[i]['id'], 0)).count()
_ret = {}
_ret['data'] = _list
count = siteM.count()
if sql_where != '':
count = siteC.where(sql_where).count()
else:
count = siteC.count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getWeb'
_page['p'] = p
_page['row'] = limit
page_args_tpl = ''
page_args_tpl += ','+type_id+''
if search != '':
page_args_tpl += ',"'+search+'"'
_page['args_tpl'] = page_args_tpl
_ret['page'] = mw.getPage(_page)
return mw.getJson(_ret)
@@ -973,6 +980,9 @@ class site_api:
siteInfo = mw.M('sites').where(
'name=?', (siteName,)).field('id,name,path').find()
path = self.getSitePath(siteName)
if path == '':
return mw.returnJson(False, '【'+siteName+'】配置文件,异常!')
srcPath = siteInfo['path']
# 检测acme是否安装
@@ -2201,7 +2211,10 @@ location ^~ {from} {\n\
if os.path.exists(file):
conf = mw.readFile(file)
rep = '\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
find_cnf = re.search(rep, conf)
if not find_cnf:
return ''
path = find_cnf.groups()[0]
return path
return ''
@@ -2300,9 +2313,15 @@ location ^~ {from} {\n\
def getSitePhpVersion(self, siteName):
conf = mw.readFile(self.getHostConf(siteName))
rep = "enable-php-(.*)\.conf"
tmp = re.search(rep, conf).groups()
find_php_cnf = re.search(rep, conf)
def_pver = '00'
if find_php_cnf:
tmp = find_php_cnf.groups()
def_pver = tmp[0]
data = {}
data['phpversion'] = tmp[0]
data['phpversion'] = def_pver
return mw.getJson(data)
def getIndex(self, sid):
+9 -8
View File
@@ -299,7 +299,8 @@ class system_api:
data_list = data.strip().split("\n")
mac_version = ''
for x in data_list:
mac_version += x.split("\t")[1] + ' '
xlist = x.split("\t")
mac_version += xlist[len(xlist)-1] + ' '
arch_ver = mw.execShell("arch")
return mac_version + " (" + arch_ver[0].strip() + ")"
@@ -366,15 +367,15 @@ class system_api:
mem = psutil.virtual_memory()
if mw.getOs() == 'darwin':
memInfo = {
'memTotal': mem.total / 1024 / 1024
'memTotal': mem.total,
}
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
else:
memInfo = {
'memTotal': mem.total / 1024 / 1024,
'memFree': mem.free / 1024 / 1024,
'memBuffers': mem.buffers / 1024 / 1024,
'memCached': mem.cached / 1024 / 1024
'memTotal': mem.total,
'memFree': mem.free,
'memBuffers': mem.buffers,
'memCached': mem.cached
}
memInfo['memRealUsed'] = memInfo['memTotal'] - \
@@ -558,9 +559,9 @@ class system_api:
networkInfo['upTotal'] = networkIo[0]
networkInfo['downTotal'] = networkIo[1]
networkInfo['up'] = round(float(
networkIo[0] - session['up']) / 1024 / (ntime - session['otime']), 2)
networkIo[0] - session['up']) / (ntime - session['otime']), 2)
networkInfo['down'] = round(
float(networkIo[1] - session['down']) / 1024 / (ntime - session['otime']), 2)
float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
networkInfo['downPackets'] = networkIo[3]
networkInfo['upPackets'] = networkIo[2]
+1 -1
View File
@@ -20,7 +20,7 @@ import requests
class vip_api:
api_url = 'https://wo.midoks.me/api/wp-json/vip'
api_url = 'https://wo.midoks.icu/api/wp-json/vip'
def __init__(self):
pass
+3 -1
View File
@@ -7,9 +7,11 @@
/etc/init.d/mw default | 显示登录信息
/etc/init.d/mw db | 快捷连接数据库
----------------------------------------
mw open | 开启面板
mw close | 关闭面板
mw debug | 开发测试
mw venv | 进入虚拟环境
mw venv | 进入虚拟环境
mw mirror | 切换镜像
mw install_app | 快捷安装常用软件
mw update | 更新到正式
+18 -18
View File
@@ -29,24 +29,24 @@ cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |PHP82 |
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |PHP82 |PHP83 |
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

+25
View File
@@ -0,0 +1,25 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('data_query');">服务</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(300);
resetPluginWinWidth(380);
pluginService('data_query', $('.plugin_version').attr('version'));
</script>
+97
View File
@@ -0,0 +1,97 @@
# coding:utf-8
import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'data_query'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
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 status():
return 'start'
def appOp(method):
return 'ok'
def start():
return appOp('start')
def stop():
return appOp('stop')
def restart():
status = appOp('restart')
return status
def reload():
return appOp('reload')
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
else:
print('error')
+36
View File
@@ -0,0 +1,36 @@
{
"hook":[
{
"tag":"menu",
"menu": {
"title":"数据管理",
"name":"data_query",
"path":"static/html/index.html",
"css_path":"static/css/data.css",
"js_path":"static/js/app.js"
}
},
{
"tag":"global_static",
"global_static": {
"title":"数据管理",
"name":"data_query",
"css_path":"static/css/ico.css"
}
}
],
"sort": 7,
"ps": "数据简单管理(memcached,redis,mongodb)",
"name": "data_query",
"title": "数据管理",
"shell": "install.sh",
"versions":"1.0",
"tip": "soft",
"checks": "server/data_query",
"path": "server/data_query",
"display": 1,
"author": "midoks",
"date": "2024-01-22",
"type": 0,
"pid": "2"
}
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source
mkdir -p $serverPath/data_query
echo "${VERSION}" > $serverPath/data_query/version.pl
echo '安装完成'
}
Uninstall_App()
{
rm -rf $serverPath/data_query
echo "卸载成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+253
View File
@@ -0,0 +1,253 @@
# coding:utf-8
# https://pypi.org/project/pymemcache/
# https://pymemcache.readthedocs.io/en/latest/getting_started.html#using-a-client-pool
import sys
import io
import os
import time
import re
import json
import pymemcache
sys.path.append(os.getcwd() + "/class/core")
import mw
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class nosqlMemcached():
__DB_PASS = None
__DB_USER = None
__DB_PORT = 11211
__DB_HOST = '127.0.0.1'
__DB_CONN = None
__DB_ERR = None
__DB_LOCAL = None
def __init__(self):
self.__config = self.get_options(None)
def conn(self):
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
mem_path = "{}/memcached".format(mw.getServerDir())
if not os.path.exists(mem_path): return False
if not self.__DB_LOCAL:
self.__DB_PORT = int(self.__config['port'])
try:
self.__DB_CONN = pymemcache.client.base.PooledClient((self.__DB_HOST,self.__DB_PORT), max_pool_size=4)
return self.__DB_CONN
except pymemcache.exceptions.MemcacheError:
return False
except Exception:
self.__DB_ERR = mw.getTracebackInfo()
return False
# 获取配置项
def get_options(self, get=None):
result = {}
mem_content = mw.readFile("{}/memcached/memcached.env".format(mw.getServerDir()))
if not mem_content: return False
keys = ["bind", "PORT"]
rep = 'PORT\s*=\s*(.*)'
port_re = re.search(rep, mem_content)
if port_re:
result['port'] = int(port_re.groups()[0].strip())
else:
result['port'] = 11211
return result
def set_host(self, host, port, prefix=''):
self.__DB_HOST = host
self.__DB_PORT = int(port)
self.__DB_PREFIX = prefix
self.__DB_LOCAL = 1
return self
@singleton
class nosqlMemcachedCtr():
def __init__(self):
pass
def getInstanceBySid(self, sid = 0):
instance = nosqlMemcached()
return instance
def getItems(self, args):
sid = args['sid']
mem_instance = self.getInstanceBySid(sid).conn()
if mem_instance is False:
return mw.returnData(False,'无法链接')
result = {}
m_items = mem_instance.stats('items')
item_no = []
for i in m_items:
item_match = b'items:(\d*?):number'
item_match_re = re.search(item_match, i)
if item_match_re:
v = item_match_re.groups()[0].strip()
v_str = v.decode()
if not v_str in item_no:
item_no.append(v_str)
if len(item_no) == 0:
item_no = [0]
result['items'] = item_no
return mw.returnData(True,'ok', result)
def getKeyList(self, args):
sid = args['sid']
mem_instance = self.getInstanceBySid(sid).conn()
if mem_instance is False:
return mw.returnData(False,'无法链接')
p = 1
size = 10
if 'p' in args:
p = args['p']
if 'size' in args:
size = args['size']
item_id = args['item_id']
if item_id == '0':
return mw.returnData(False,'ok')
m_items = mem_instance.stats('items')
item_key = 'items:%s:number' % item_id
item_key_b = item_key.encode("utf-8")
m_items_v = m_items[item_key_b]
start = (p-1)*size
end = start+size
if end > m_items_v:
end = m_items_v
all_key = mem_instance.stats('cachedump', str(item_id) , str(0))
# print(all_key)
all_key_list = []
cur_time_t = time.time()
for k in all_key:
t = {}
t['k'] = k.decode("utf-8")
v = all_key[k].decode("utf-8")
v = v.strip('[').strip(']').split(';')
t['s'] = v[0]
cur_time = v[1].strip().split(' ')[0]
if int(cur_time) != 0 :
t['t'] = int(cur_time) - int(cur_time_t)
else:
t['t'] = 0
all_key_list.append(t)
# print(len(all_key_list))
# print(start,end)
return_all_key = all_key_list[start:end]
for x in range(len(return_all_key)):
v = mem_instance.get(return_all_key[x]['k'])
return_all_key[x]['v'] = v.decode('utf-8')
result = {}
result['list'] = return_all_key
result['p'] = p
page_args = {}
page_args['count'] = len(all_key_list)
page_args['tojs'] = 'memcachedGetKeyList'
page_args['p'] = p
page_args['row'] = size
result['page'] = mw.getPage(page_args)
return mw.returnData(True,'ok', result)
def delVal(self, args):
sid = args['sid']
mem_instance = self.getInstanceBySid(sid).conn()
if mem_instance is False:
return mw.returnData(False,'无法链接')
key = args['key']
mem_instance.delete(key)
return mw.returnData(True,'删除成功!')
def setKv(self, args):
sid = args['sid']
mem_instance = self.getInstanceBySid(sid).conn()
if mem_instance is False:
return mw.returnData(False,'无法链接')
key = args['key']
val = args['val']
endtime = args['endtime']
mem_instance.set(key, val, int(endtime))
return mw.returnData(True,'设置成功!')
def clear(self, args):
sid = args['sid']
mem_instance = self.getInstanceBySid(sid).conn()
if mem_instance is False:
return mw.returnData(False,'无法链接')
mem_instance.flush_all()
return mw.returnData(True,'清空成功!')
# ---------------------------------- run ----------------------------------
# 获取 memcached 列表
def get_items(args):
t = nosqlMemcachedCtr()
return t.getItems(args)
def get_key_list(args):
t = nosqlMemcachedCtr()
return t.getKeyList(args)
def del_val(args):
t = nosqlMemcachedCtr()
return t.delVal(args)
def set_kv(args):
t = nosqlMemcachedCtr()
return t.setKv(args)
def clear(args):
t = nosqlMemcachedCtr()
return t.clear(args)
# 测试
def test(args):
sid = args['sid']
t = nosqlMemcachedCtr()
print(t.get_options())
print("test")
return 'ok'
# ---------------------------------- run ----------------------------------
+254
View File
@@ -0,0 +1,254 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import pymongo
import json
from bson.objectid import ObjectId
from bson.json_util import dumps
sys.path.append(os.getcwd() + "/class/core")
import mw
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class nosqlMongodb():
__DB_PASS = None
__DB_USER = None
__DB_PORT = 6379
__DB_HOST = '127.0.0.1'
__DB_CONN = None
__DB_ERR = None
__DB_LOCAL = None
def __init__(self):
self.__config = self.get_options(None)
def mgdb_conn(self):
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
mgdb_path = "{}/mongodb".format(mw.getServerDir())
if not os.path.exists(mgdb_path): return False
if not self.__DB_LOCAL:
self.__DB_PORT = int(self.__config['port'])
# print(self.__DB_HOST,self.__DB_PORT, self.__DB_PASS)
try:
self.__DB_CONN = pymongo.MongoClient(host=self.__DB_HOST, port=self.__DB_PORT, maxPoolSize=10)
self.__DB_CONN.admin.command('ping')
return self.__DB_CONN
except pymongo.errors.ConnectionFailure:
return False
except Exception:
self.__DB_ERR = mw.get_error_info()
return False
# 获取配置项
def get_options(self, get=None):
result = {}
mgdb_content = mw.readFile("{}/mongodb/mongodb.conf".format(mw.getServerDir()))
if not mgdb_content: return False
keys = ["bind_ip", "port"]
result['host'] = '127.0.0.1'
rep = 'port\s*=\s*(.*)'
ip_re = re.search(rep, mgdb_content)
if ip_re:
result['port'] = int(ip_re.groups()[0].strip())
else:
result['port'] = 27017
return result
def set_host(self, host, port, name, username, password, prefix=''):
self.__DB_HOST = host
self.__DB_PORT = int(port)
self.__DB_NAME = name
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
self.__DB_USER = str(username)
self._USER = str(username)
self.__DB_PASS = str(password)
self.__DB_PREFIX = prefix
self.__DB_LOCAL = 1
return self
@singleton
class nosqlMongodbCtr():
def __init__(self):
pass
def getInstanceBySid(self, sid = 0):
instance = nosqlMongodb()
return instance
def getDbList(self, args):
sid = args['sid']
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
if mgdb_instance is False:
return mw.returnData(False,'无法链接')
result = {}
doc_list = mgdb_instance.list_database_names()
rlist = []
for x in doc_list:
if not x in ['admin', 'config', 'local']:
rlist.append(x)
result['list'] = rlist
return mw.returnData(True,'ok', result)
def getCollectionsList(self, args):
sid = args['sid']
name = args['name']
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
if mgdb_instance is False:
return mw.returnData(False,'无法链接')
result = {}
collections = mgdb_instance[name].list_collection_names()
result['collections'] = collections
return mw.returnData(True,'ok', result)
def getDataList(self, args):
sid = args['sid']
db = args['db']
collection = args['collection']
p = 1
size = 10
if 'p' in args:
p = args['p']
if 'size' in args:
size = args['size']
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
if mgdb_instance is False:
return mw.returnData(False,'无法链接')
db_instance = mgdb_instance[db]
collection_instance = db_instance[collection]
start_index = (p - 1) * size
end_index = p * size
args_where = args['where']
where = {}
if 'field' in args_where:
mg_field = args_where['field']
if mg_field == '_id':
mg_value = ObjectId(args_where['value'])
where[mg_field] = mg_value
else:
mg_value = args_where['value']
where[mg_field] = re.compile(mg_value)
# print(where)
result = collection_instance.find(where).skip(start_index).limit(size).sort({'_id':-1})
count = collection_instance.count_documents(where)
d = []
for document in result:
d.append(document)
doc_str_json = dumps(d)
result = json.loads(doc_str_json)
page_args = {}
page_args['count'] = count
page_args['tojs'] = 'mongodbDataList'
page_args['p'] = p
page_args['row'] = size
rdata = {}
rdata['page'] = mw.getPage(page_args)
rdata['list'] = result
rdata['count'] = count
rdata['soso_field'] = ''
if 'field' in args_where:
rdata['soso_field'] = args_where['field']
return mw.returnData(True,'ok', rdata)
def delById(self,args):
sid = args['sid']
db = args['db']
collection = args['collection']
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
if mgdb_instance is False:
return mw.returnData(False,'无法链接')
db_instance = mgdb_instance[db]
collection_instance = db_instance[collection]
_id = args['_id']
result = collection_instance.delete_one({"_id": ObjectId(_id)})
return mw.returnData(True,'文档删除【%d】个成功!' % result.deleted_count)
# ---------------------------------- run ----------------------------------
# 获取 mongodb databases 列表
def get_db_list(args):
t = nosqlMongodbCtr()
return t.getDbList(args)
# 获取 mongodb collections 列表
def get_collections_list(args):
t = nosqlMongodbCtr()
return t.getCollectionsList(args)
def get_data_list(args):
t = nosqlMongodbCtr()
return t.getDataList(args)
def set_kv(args):
t = nosqlMongodbCtr()
return t.setKv(args)
def del_val(args):
t = nosqlMongodbCtr()
return t.delVal(args)
def batch_del_val(args):
t = nosqlMongodbCtr()
return t.batchDelVal(args)
def clear_flushdb(args):
t = nosqlMongodbCtr()
return t.clearFlushDB(args)
def del_by_id(args):
t = nosqlMongodbCtr()
return t.delById(args)
# 测试
def test(args):
sid = args['sid']
t = nosqlMongodbCtr()
print(t.get_options())
print("test")
return 'ok'
+347
View File
@@ -0,0 +1,347 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import redis
sys.path.append(os.getcwd() + "/class/core")
import mw
# def getPluginName():
# return 'data_query'
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class nosqlRedis():
__DB_PASS = None
__DB_USER = None
__DB_PORT = 6379
__DB_HOST = '127.0.0.1'
__DB_CONN = None
__DB_ERR = None
__DB_LOCAL = None
def __init__(self):
self.__config = self.get_options(None)
def redis_conn(self, db_idx=0):
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
redis_path = "{}/redis".format(mw.getServerDir())
if not os.path.exists(redis_path): return False
if not self.__DB_LOCAL:
self.__DB_PASS = self.__config['requirepass']
self.__DB_PORT = int(self.__config['port'])
# print(self.__DB_HOST,self.__DB_PORT, self.__DB_PASS)
try:
redis_pool = redis.ConnectionPool(host=self.__DB_HOST, port=self.__DB_PORT, password=self.__DB_PASS, db=db_idx, socket_timeout=3)
self.__DB_CONN = redis.Redis(connection_pool=redis_pool)
self.__DB_CONN.ping()
return self.__DB_CONN
except redis.exceptions.ConnectionError:
return False
except Exception:
self.__DB_ERR = mw.getTracebackInfo()
return False
# 获取配置项
def get_options(self, get=None):
result = {}
redis_conf = mw.readFile("{}/redis/redis.conf".format(mw.getServerDir()))
if not redis_conf: return False
keys = ["bind", "port", "timeout", "maxclients", "databases", "requirepass", "maxmemory"]
for k in keys:
v = ""
rep = "\n%s\s+(.+)" % k
group = re.search(rep, redis_conf)
if not group:
if k == "maxmemory":
v = "0"
if k == "maxclients":
v = "10000"
if k == "requirepass":
v = ""
else:
if k == "maxmemory":
v = int(group.group(1).strip("mb"))
else:
v = group.group(1)
result[k] = v
return result
def set_host(self, host, port, name, username, password, prefix=''):
self.__DB_HOST = host
self.__DB_PORT = int(port)
self.__DB_NAME = name
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
self.__DB_USER = str(username)
self._USER = str(username)
self.__DB_PASS = str(password)
self.__DB_PREFIX = prefix
self.__DB_LOCAL = 1
return self
@singleton
class nosqlRedisCtr():
def __init__(self):
pass
def getInstanceBySid(self, sid = 0):
instance = nosqlRedis()
return instance
def getList(self, args):
sid = args['sid']
redis_instance = self.getInstanceBySid(sid).redis_conn(0)
if redis_instance is False:
return mw.returnData(False,'无法链接')
redis_info = redis_instance.info()
is_cluster = redis_info.get("cluster_enabled", 0)
if is_cluster != 0:
return mw.returnData(False, "当前不支持连接redis集群!")
db_num = 16
if sid != 0:
db_num = 1000
result = []
for x in range(0, db_num):
data = {}
data['id'] = x
data['name'] = 'DB{}'.format(x)
try:
redis_instance = self.getInstanceBySid(sid).redis_conn(x)
data['keynum'] = redis_instance.dbsize()
result.append(data)
except:
break
return mw.returnData(True,'ok', result)
def getDbKeyList(self, args):
p = 1
size = 10
if not 'sid' in args:
return mw.returnData(False, "缺少参数!sid")
if 'p' in args:
p = args['p']
if p < 1:
p = 1
if p > 10:
p = 10
if 'size' in args:
size = args['size']
sid = args['sid']
idx = args['idx']
search = '*'
if 'search' in args and args['search'] != '':
search = args['search']
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
total = redis_instance.dbsize()
if search != '*':
keylist = redis_instance.keys(search)
total = len(keylist)
else:
keys = redis_instance.scan(cursor=0, match="{}".format(search), count=p*size)
keylist = keys[1]
slist = keylist[(p - 1) * size:p*size]
items = []
for key in slist:
item = {}
try:
item['name'] = key.decode()
except Exception as e:
item['name'] = str(key)
item['endtime'] = redis_instance.ttl(key)
item['type'] = redis_instance.type(key).decode()
if item['type'] == 'string':
try:
item['val'] = redis_instance.get(key).decode()
except Exception as e:
item['val'] = str(redis_instance.get(key))
elif item['type'] == 'hash':
if redis_instance.hlen(key) > 500:
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.hlen(key))
else:
item['val'] = str(redis_instance.hgetall(key))
elif item['type'] == 'list':
if redis_instance.llen(key) > 500:
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.llen(key))
else:
item['val'] = str(redis_instance.lrange(key, 0, -1))
elif item['type'] == 'set':
if redis_instance.scard(key) > 500:
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.scard(key))
else:
item['val'] = str(redis_instance.smembers(key))
elif item['type'] == 'zset':
if redis_instance.zcard(key) > 500:
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.zcard(key))
else:
item['val'] = str(redis_instance.zrange(key, 0, -1, withscores=True))
else:
item['val'] = ''
try:
item['len'] = redis_instance.strlen(key)
except:
item['len'] = len(item['val'])
items.append(item)
page_args = {}
page_args['count'] = total
page_args['tojs'] = 'redisGetKeyList'
page_args['p'] = p
page_args['row'] = size
rdata = {}
rdata['page'] = mw.getPage(page_args)
rdata['data'] = items
return mw.returnData(True,'ok',rdata)
def setKv(self,args):
if not 'name' in args:
return mw.returnData(False, "缺少参数!name")
if not 'val' in args:
return mw.returnData(False, "缺少参数!val")
if not 'idx' in args:
return mw.returnData(False, "缺少参数!idx")
sid = args['sid']
idx = args['idx']
name = args["name"]
val = args["val"]
endtime = args["endtime"]
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
redis_info = redis_instance.info()
if redis_info['role'] == 'slave':
return mw.returnData(False,'从库不能写操作!')
if endtime != '0':
redis_instance.set(name, val, int(endtime))
else:
redis_instance.set(name, val)
return mw.returnData(True,'操作成功')
def delVal(self, args):
sid = args['sid']
idx = args['idx']
name = args["name"]
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
redis_info = redis_instance.info()
if redis_info['role'] == 'slave':
return mw.returnData(False,'从库不能删除操作!')
redis_instance.delete(name)
return mw.returnData(True,'操作成功')
def batchDelVal(self, args):
sid = args['sid']
idx = args['idx']
keys = args["keys"]
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
redis_info = redis_instance.info()
if redis_info['role'] == 'slave':
return mw.returnData(False,'从库不能删除操作!')
for k in keys:
redis_instance.delete(k)
return mw.returnData(True,'操作成功')
def clearFlushDB(self, args):
sid = args['sid']
idxs = args['idxs']
for idx in idxs:
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
redis_info = redis_instance.info()
if redis_info['role'] == 'slave':
return mw.returnData(False,'从库不能清空操作!')
redis_instance.flushdb()
return mw.returnData(True,'操作成功')
# ---------------------------------- run ----------------------------------
# 获取 redis databases 列表
def get_list(args):
t = nosqlRedisCtr()
return t.getList(args)
# 获取 redis key 列表
def get_dbkey_list(args):
t = nosqlRedisCtr()
return t.getDbKeyList(args)
def set_kv(args):
t = nosqlRedisCtr()
return t.setKv(args)
def del_val(args):
t = nosqlRedisCtr()
return t.delVal(args)
def batch_del_val(args):
t = nosqlRedisCtr()
return t.batchDelVal(args)
def clear_flushdb(args):
t = nosqlRedisCtr()
return t.clearFlushDB(args)
# 测试
def test(args):
sid = args['sid']
t = nosqlRedis()
print(t.get_options())
print("test")
return 'ok'
# ---------------------------------- run ----------------------------------
+301
View File
@@ -0,0 +1,301 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import pymongo
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class nosqlMySQL():
__DB_PASS = None
__DB_USER = None
__DB_PORT = 3306
__DB_HOST = '127.0.0.1'
__DB_CONN = None
__DB_ERR = None
__DB_SOCKET = None
__DB_LOCAL = None
def __init__(self):
self.__config = self.get_options(None)
def conn(self):
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
my_path = "{}/mysql".format(mw.getServerDir())
if not os.path.exists(my_path): return False
if not self.__DB_LOCAL:
# print(self.__config)
self.__DB_PORT = int(self.__config['port'])
self.__DB_USER = self.__config['username']
self.__DB_PASS = self.__config['password']
self.__DB_SOCKET = self.__config['socket']
try:
db = mw.getMyORM()
db.setPort(self.__DB_PORT)
db.setPwd(self.__DB_PASS)
db.setUser(self.__DB_USER)
if self.__DB_SOCKET != '':
db.setSocket(self.__DB_SOCKET)
return db
except Exception:
self.__DB_ERR = mw.get_error_info()
return False
def sqliteDb(self,dbname='databases'):
my_root_path = mw.getServerDir() +'/mysql'
name = 'mysql'
conn = mw.M(dbname).dbPos(my_root_path, name)
return conn
# 获取配置项
def get_options(self, get=None):
result = {}
my_cnf_path = "{}/mysql/etc/my.cnf".format(mw.getServerDir())
my_content = mw.readFile(my_cnf_path)
if not my_content: return False
mysql_pass = self.sqliteDb('config').where('id=?', (1,)).getField('mysql_root')
result['password'] = mysql_pass
result['username'] = 'root'
keys = ["bind_ip", "port"]
result['host'] = '127.0.0.1'
rep = 'port\s*=\s*(.*)'
port_re = re.search(rep, my_content)
if port_re:
result['port'] = int(port_re.groups()[0].strip())
else:
result['port'] = 3306
socket_rep = 'socket\s*=\s*(.*)'
socket_re = re.search(socket_rep, my_content)
if socket_re:
result['socket'] = socket_re.groups()[0].strip()
else:
result['socket'] = ''
return result
def set_host(self, host, port, name, username, password, prefix=''):
self.__DB_HOST = host
self.__DB_PORT = int(port)
self.__DB_NAME = name
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
self.__DB_USER = str(username)
self._USER = str(username)
self.__DB_PASS = str(password)
self.__DB_PREFIX = prefix
self.__DB_LOCAL = 1
return self
@singleton
class nosqlMySQLCtr():
def __init__(self):
pass
def getInstanceBySid(self, sid = 0):
instance = nosqlMySQL()
return instance
def getDbList(self, args):
sid = args['sid']
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
result = {}
db_list = my_instance.query('show databases')
rlist = []
for x in db_list:
if not x['Database'] in ['information_schema', 'mysql', 'performance_schema','sys']:
rlist.append(x['Database'])
result['list'] = rlist
return mw.returnData(True,'ok', result)
def getTableList(self, args):
sid = args['sid']
db = args['db']
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
sql = "select * from information_schema.tables where table_schema = '"+db+"'"
table_list = my_instance.query(sql)
# print(table_list)
rlist = []
for x in table_list:
# print(x['TABLE_NAME'])
rlist.append(x['TABLE_NAME'])
result = {}
result['list'] = rlist
return mw.returnData(True,'ok', result)
def getDataList(self, args):
sid = args['sid']
db = args['db']
table = args['table']
p = 1
size = 10
if 'p' in args:
p = args['p']
if 'size' in args:
size = args['size']
start_index = (p - 1) * size
args_where = {}
where_sql = ''
if 'where' in args:
args_where = args['where']
if 'field' in args_where:
if args_where['field'] == 'id' or args_where['field'].find('id')>-1:
where_sql = ' where '+args_where['field'] + " = '"+args_where['value']+"' "
else:
where_sql = ' where '+args_where['field'] + " like '%"+args_where['value']+"%' "
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
my_instance.setDbName(db)
sql = 'select count(*) as num from ' + table + where_sql
# print(sql)
count_result = my_instance.query(sql)
count = count_result[0]['num']
sql = 'select * from ' + table + where_sql + ' limit '+str(start_index)+',10';
# print(sql)
result = my_instance.query(sql)
for i in range(len(result)):
for f in result[i]:
result[i][f] = str(result[i][f])
# print(result)
page_args = {}
page_args['count'] = count
page_args['tojs'] = 'mysqlGetDataList'
page_args['p'] = p
page_args['row'] = size
rdata = {}
rdata['page'] = mw.getPage(page_args)
rdata['list'] = result
rdata['count'] = count
rdata['soso_field'] = ''
if 'field' in args_where:
rdata['soso_field'] = args_where['field']
return mw.returnData(True,'ok', rdata)
def showProcessList(self,args):
sql = 'show processlist';
sid = args['sid']
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
result = my_instance.query(sql)
rdata = {}
rdata['list'] = result
return mw.returnData(True,'ok', rdata)
def showStatusList(self,args):
sql = 'show status';
sid = args['sid']
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
result = my_instance.query(sql)
rdata = {}
rdata['list'] = result
return mw.returnData(True,'ok', rdata)
def showStatsList(self, args):
sql = "show status like 'Com_%'";
sid = args['sid']
my_instance = self.getInstanceBySid(sid).conn()
if my_instance is False:
return mw.returnData(False,'无法链接')
result = my_instance.query(sql)
rdata = {}
rdata['list'] = result
return mw.returnData(True,'ok', rdata)
# ---------------------------------- run ----------------------------------
# 获取 mysql 列表
def get_db_list(args):
t = nosqlMySQLCtr()
return t.getDbList(args)
# 获取 mysql 列表
def get_table_list(args):
t = nosqlMySQLCtr()
return t.getTableList(args)
def get_data_list(args):
t = nosqlMySQLCtr()
return t.getDataList(args)
def get_proccess_list(args):
t = nosqlMySQLCtr()
return t.showProcessList(args)
def get_status_list(args):
t = nosqlMySQLCtr()
return t.showStatusList(args)
def get_stats_list(args):
t = nosqlMySQLCtr()
return t.showStatsList(args)
# 测试
def test(args):
sid = args['sid']
t = nosqlMySQLCtr()
print(t.get_options())
print("test")
return 'ok'
+48
View File
@@ -0,0 +1,48 @@
.main-content .safe {
position: relative;
}
.mask_layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgb(255 255 255 / 60%);
z-index: 9998;
}
.mask_layer .prompt_description {
width: 350px;
height: 60px;
line-height: 60px;
text-align: center;
position: absolute;
left: 50%;
top: 50%;
margin-top: -25px;
margin-left: -175px;
background: #fff;
box-shadow: 1px 1px 50px rgb(0 0 0 / 30%);
border: 1px solid #eee;
border-radius: 2px;
font-size: 13px;
}
#mongodb_search xm-select {
min-height: 30px;
line-height: 30px;
}
#mongodb_search xm-select .xm-label .xm-label-block{
height: 20px;
line-height: 20px;
}
#mongodb td:last-child, th:last-child {
width: 44px;
position:sticky;
right:0; /* 首行永远固定在左侧 */
z-index:1;
background-color:white;
}
+11
View File
@@ -0,0 +1,11 @@
/* menu start */
.menu .current .menu_plugin_data_query:hover {
background-image: url("/plugins/file?name=data_query&f=ico.png");
}
.menu .menu_plugin_data_query {
background-image: url("/plugins/file?name=data_query&f=ico.png");
}
/* menu end */
+294
View File
@@ -0,0 +1,294 @@
<div class="main-content" style="min-height: 389px;">
<div class="container-fluid" style="padding-bottom: 50px;">
<div id="cutTab" class="pos-box bgw mtb15" style="height:45px">
<div class="tab-list">
<div class="tabs-item active" data-name="redis">Redis</div>
<div class="tabs-item" data-name="mongodb">Mongodb</div>
<div class="tabs-item" data-name="memcached">Memcached</div>
<div class="tabs-item" data-name="mysql">MySQL</div>
</div>
</div>
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view safe" style="overflow: hidden;">
<div class="mask_layer" style="display:none;">
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft">点击安装</a></div>
</div>
<!-- mysql start -->
<!-- show w-full -->
<div class="tab-con hide" id="mysql" style="padding: 0px;">
<div class="col-md-12" style="padding: 0px;overflow: hidden;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<div class="server_list" style="float:left;">
<select name="sid" class="bt-input-text c5 mr5">
<option value="0">本地服务器</option>
</select>
</div>
<div class="mysql_db_list" style="float:left;">
<select name="mysql_db" class="bt-input-text c5 mr5">
<option value="0">数据库空</option>
</select>
</div>
<div class="mysql_table_list" style="float:left;">
<select name="mysql_table" class="bt-input-text c5 mr5">
<option value="0">数据表空</option>
</select>
</div>
<div class="field" style="float:left;">
<select name="mysql_field_key" class="bt-input-text c5 mr5" style="width:80px;">
<option value="0">无字段</option>
</select>
</div>
<div class="value" style="float:left;">
<input name="mysql_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
</div>
<button type="button" class="mysql_find btn btn-success btn-sm mr5 ml5" style="float:right;">
<span>查找</span>
</button>
</div>
</div>
<div style="position: relative;">
<div id="mysql_table" class="mysql_table divtable mtb10">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th><span>编号</span></th>
<th><span>操作类型</span></th>
<th><span>详情</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="mysql_list_page page">
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
</div>
</div>
<div class="col-md-12" style="padding-left: 3px;">
<div id="mysql_list_tab" style="padding-top:0px;">
<div class="tab-nav">
<span data-name="proccess" class="on">进程</span>
<span data-name="status" class="">状态</span>
<span data-name="stats" class="">统计</span>
</div>
</div>
<div style="position: relative;">
<div id="mysql_ot_table" class="divtable">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th><span>编号</span></th>
<th><span>操作类型</span></th>
<th><span>详情</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
<!-- mysql end -->
<!-- mongodb start -->
<!-- show w-full -->
<div class="tab-con hide" id="mongodb" style="padding: 0px;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<div class="field" style="float:left;">
<select name="mongodb_field_key" class="bt-input-text c5 mr5" style="width:80px;">
<option value="0">无字段</option>
</select>
</div>
<div class="value" style="float:left;">
<input name="mongodb_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
</div>
<button type="button" class="mongodb_find btn btn-success btn-sm mr5 ml5" style="float:right;">
<span>查找</span>
</button>
</div>
<div class="pull-right" style="padding-top: 5px;">
<div class="server_list" style="float:left;">
<select name="sid" class="bt-input-text c5 mr5">
<option value="0">本地服务器</option>
</select>
</div>
<div class="db_list" style="float:left;">
<select name="db" class="bt-input-text c5 mr5">
<option value="0">空</option>
</select>
</div>
<div class="search" id="mongodb_search"></div>
</div>
</div>
<div style="position: relative;">
<div id="mongodb_table" class="mongodb_table divtable mtb10">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th><span>编号</span></th>
<th><span>操作类型</span></th>
<th><span>详情</span></th>
<th style="text-align:right;"><span>操作</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="mongodb_list_page page">
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
</div>
</div>
<!-- mongodb end -->
<!-- redis start -->
<div class="tab-con show w-full" id="redis" style="padding: 0px;">
<div id="redis_ctr" style="position: relative;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<button id="redis_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
<span>添加key</span>
</button>
<button id="redis_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
<span>清空数据库</span>
</button>
</div>
</div>
<div id="redis_list_tab" style="padding-top:10px;">
<div class="tab-nav">
<!-- <span data-id="0" class="on">DB0(0)</span> -->
</div>
</div>
<div class="tootls_group tootls_top">
<div class="pull-left"></div>
<div class="pull-right" style="padding-top: 5px;">
<div class="search">
<input id="redis_ksearch" type="text" class="search_input" placeholder="请输入键名称">
<span id="redis_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
</div>
</div>
</div>
<div class="divtable mtb10 redis_table_content">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
<th><span>键</span></th>
<th><span>值</span></th>
<th><span>数据类型</span></th>
<th><span>数据长度</span></th>
<th><span>有效期</span></th>
<th style="text-align:right;"><span>操作</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="tootls_group tootls_bottom">
<div class="pull-left">
<button id="redis_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
</div>
<div class="pull-right">
<div class="page redis_list_page">
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
</div>
</div>
</div>
</div>
<!-- redis end -->
<!-- memcached start -->
<div class="tab-con hide" id="memcached" style="padding: 0px;">
<div id="memcached_ctr" style="position: relative;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<button id="memcached_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
<span>添加key</span>
</button>
<button id="memcached_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
<span>清空</span>
</button>
</div>
<div class="pull-right" style="padding-top: 5px;">
<div class="item_list" style="float:left;">
<select name="item" class="bt-input-text c5 mr5">
<option value="0">空</option>
</select>
</div>
<div class="search">
<input id="memcached_ksearch" type="text" class="search_input" placeholder="请输入键名称">
<span id="memcached_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
</div>
</div>
</div>
<div class="divtable mtb10 memcached_table_content">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
<th><span>键</span></th>
<th><span>值</span></th>
<th><span>数据长度</span></th>
<th><span>有效期</span></th>
<th style="text-align:right;"><span>操作</span></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="tootls_group tootls_bottom">
<div class="pull-left">
<button id="memcached_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
</div>
<div class="pull-right">
<div class="page memcached_list_page">
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
</div>
</div>
</div>
</div>
<!-- memcached end -->
</div>
</div>
</div>
+1281
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -15,5 +15,5 @@
"home": "https://docker.io",
"doc1":"https://docker-py.readthedocs.io/",
"type": 0,
"pid": "2"
"pid": "4"
}
+1 -1
View File
@@ -38,7 +38,7 @@ Install_App()
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
HTTP_PREFIX="https://"
if [ ! -z "$cn" ];then
HTTP_PREFIX="https://ghproxy.com/"
HTTP_PREFIX="https://mirror.ghproxy.com/"
fi
# FlameGraph start
+1 -1
View File
@@ -20,7 +20,7 @@
# http://localhost/?code=M.C106_BAY.2.3e12c859-6107-0c5b-9ef4-14b3fb8269ba&state=JzHdzHXmA7x6zl7Be6cJ6uOlf9Bg69
# python3 /www/mdserver-web/plugins/gdrive/index.py site bbs.midoks.me 3
# python3 /www/mdserver-web/plugins/gdrive/index.py site bbs.midoks.icu 3
# python3 /www/mdserver-web/plugins/gdrive/index.py database t1 3
# python3 /www/server/mdserver-web/plugins/msonedrive/index.py path
# /Users/midoks/Desktop/dev/python 3
+5 -1
View File
@@ -8,6 +8,10 @@ GIT_SDIR="{$CODE_DIR}"
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
if [ ! -d $GIT_USER_DIR ];then
mkdir -p $GIT_USER_DIR
chown -R www:www $GIT_USER_DIR
fi
git config --global credential.helper store
git config --global pull.rebase false
@@ -34,7 +38,7 @@ if [ ! -d $WEB_PATH ];then
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
else
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
rsync -vauP --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
fi
+3 -1
View File
@@ -15,7 +15,9 @@ if [ ! -d $GIT_PROJECT_DIR ];then
fi
unset GIT_DIR
git config pull.rebase false
git config pull.rebase true
git config credential.helper store
cd $GIT_PROJECT_DIR && git pull
+1 -1
View File
@@ -36,7 +36,7 @@ Install_App()
if [ "${LOCAL_ADDR}" == "cn" ];then
if [ ! -f ${APP_DIR}/haproxy-${VERSION}.tar.gz ];then
wget -O ${APP_DIR}/haproxy-${VERSION}.tar.gz https://dl.midoks.me/soft/haproxy/haproxy-${VERSION}.tar.gz
wget -O ${APP_DIR}/haproxy-${VERSION}.tar.gz https://dl.midoks.icu/soft/haproxy/haproxy-${VERSION}.tar.gz
fi
fi
+1
View File
@@ -12,6 +12,7 @@
<p onclick="myPerfOpt();">性能优化</p>
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mariadb',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="myBinLogs();">BINLOG</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
+202 -33
View File
@@ -90,6 +90,12 @@ def getDataDir():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getPidFile():
file = getConf()
@@ -294,6 +300,53 @@ def binLog():
mw.writeFile(conf, con)
return mw.returnJson(True, '设置成功!')
def binLogList():
args = getArgs()
data = checkArgs(args, ['page', 'page_size', 'tojs'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
abspath = data_dir + '/' + f
t['name'] = f
t['size'] = os.path.getsize(abspath)
t['time'] = mw.getDataFromInt(os.path.getctime(abspath))
log_bin_l.append(t)
log_bin_l = sorted(log_bin_l, key=lambda x: x['time'], reverse=True)
# print(log_bin_l)
# print(data_dir, log_bin_name)
count = len(log_bin_l)
page_start = (page - 1) * page_size
page_end = page_start + page_size
if page_end > count:
page_end = count
data = {}
page_args = {}
page_args['count'] = count
page_args['p'] = page
page_args['row'] = page_size
page_args['tojs'] = args['tojs']
data['page'] = mw.getPage(page_args)
data['data'] = log_bin_l[page_start:page_end]
return mw.getJson(data)
def cleanBinLog():
db = pMysqlDb()
@@ -302,21 +355,6 @@ def cleanBinLog():
return mw.returnJson(True, '清理BINLOG成功!')
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():
args = getArgs()
path = getDataDir()
@@ -579,7 +617,7 @@ def setMyPort():
restart()
return mw.returnJson(True, '编辑成功!')
# python3 plugins/mariadb/index.py run_info {}
def runInfo(version):
if status(version) == 'stop':
@@ -760,6 +798,8 @@ def rootPwd():
'id=?', (1,)).getField('mysql_root')
# python3 plugins/mariadb/index.py import_db_external {"file":"xx.sql","name":"demo1"}
# python3 plugins/mariadb/index.py import_db_external {"file":"db_demo1_20231221_203614 2.sql","name":"demo1"}
def importDbExternal():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
@@ -806,6 +846,9 @@ def importDbExternal():
mw.execShell(cmd)
import_sql = import_dir + tmpFile
if file.find(".sql") > -1 and file.find(".sql.gz") == -1:
import_sql = import_dir + file
if import_sql == "":
return mw.returnJson(False, '未找SQL文件')
@@ -813,12 +856,14 @@ def importDbExternal():
sock = getSocketFile()
os.environ["MYSQL_PWD"] = pwd
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p"' + \
pwd + '" ' + name + ' < "' + import_sql+'"'
# print(mysql_cmd)
os.system(mysql_cmd)
os.remove(import_sql)
if ext != 'sql':
os.remove(import_sql)
return mw.returnJson(True, 'ok')
@@ -982,7 +1027,7 @@ def syncGetDatabases():
host = user["Host"]
break
ps = mw.getMsg('INPUT_PS')
ps = vdb_name
if vdb_name == 'test':
ps = mw.getMsg('DATABASE_TEST')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
@@ -1054,12 +1099,21 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb('mysql')
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
cmd = "ALTER USER 'root'@'localhost' IDENTIFIED BY '" + password + "';"
@@ -1069,7 +1123,12 @@ def setRootPwd(version=''):
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
orm = pMysqlDb()
orm.execute("flush privileges")
return mw.returnJson(True, '数据库root密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!' + msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
@@ -1276,16 +1335,58 @@ def setDbAccess():
psdb.where('username=?', (name,)).save('accept,rw', (access, 'rw',))
return mw.returnJson(True, '设置成功!')
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
db_option = "-S " + serverdir + "/mysql.sock"
cmd_pass = serverdir + '/bin/mariadb ' + db_option + ' -uroot -e'
cmd_pass = cmd_pass + \
"\"flush privileges;use mysql;grant all privileges on *.* to 'root'@'localhost' identified by '" + pwd + "';"
cmd_pass = cmd_pass + "flush privileges;\""
data = mw.execShell(cmd_pass)
# print(data)
return True
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
pdb = pMysqlDb()
psdb = pSqliteDb('databases')
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
mw.execShell("rm -rf " + getServerDir() + "/data")
openSkipGrantTables()
appCMD(version, 'start')
time.sleep(3)
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
@@ -1588,6 +1689,13 @@ def setDbMasterAccess():
psdb.where('username=?', (username,)).save('accept', (access,))
return mw.returnJson(True, '设置成功!')
def resetMaster(version=''):
pdb = pMysqlDb()
r = pdb.execute('reset master')
isError = isSqlError(r)
if isError != None:
return isError
return mw.returnJson(True, '重置成功!')
def getMasterDbList(version=''):
args = getArgs()
@@ -1899,8 +2007,7 @@ def getMasterRepSlaveUserCmd(version):
if mode == "gtid":
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + "', " + "MASTER_LOG_FILE='" + mstatus[0]["File"] + \
"',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
clist[0]['password'] + "',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
else:
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
@@ -2186,6 +2293,58 @@ def getSlaveList(version=''):
data['data'] = dlist
return mw.getJson(data)
def trySlaveSyncBugfix(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode != 'sync-user':
return mw.returnJson(False, '仅支持【同步账户】模式')
conn = pSqliteDb('slave_sync_user')
slave_sync_data = conn.field('ip,port,user,pass,mode,cmd').select()
if len(slave_sync_data) < 1:
return mw.returnJson(False, '需要先添加【同步用户】配置!')
# print(slave_sync_data)
# 本地从库
sdb = pMysqlDb()
gtid_purged = ''
for i in range(len(slave_sync_data)):
port = slave_sync_data[i]['port']
password = slave_sync_data[i]['pass']
host = slave_sync_data[i]['ip']
user = slave_sync_data[i]['user']
# print(port, password, host)
mdb = mw.getMyORM()
mdb.setHost(host)
mdb.setPort(port)
mdb.setUser(user)
mdb.setPwd(password)
mdb.setSocket('')
# var_gtid = mdb.query('show VARIABLES like "%gtid_purged%"')
var_gtid = mdb.query('select @@global.gtid_current_pos as Value')
#print(var_gtid)
if len(var_gtid) > 0:
gtid_purged += var_gtid[0]['Value'] + ','
gtid_purged = gtid_purged.strip(',')
sql = "set @@global.gtid_slave_pos='" + gtid_purged + "'"
sdb.query('stop all slaves')
# print(sql)
sdb.query(sql)
sdb.query('start all slaves')
return mw.returnJson(True, '修复成功!')
def getSlaveSyncCmd(version=''):
root = mw.getRunDir()
@@ -2226,7 +2385,7 @@ def parseSlaveSyncCmd(cmd):
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
return a
# python3 plugins/mariadb/index.py init_slave_status {}
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
@@ -2267,7 +2426,7 @@ def initSlaveStatusSyncUser(version=''):
try:
pinfo = parseSlaveSyncCmd(cmd_sql)
except Exception as e:
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
return mw.returnJson(False, base_t + '->CMD同步命令不合规范:'+str(e))
pdb.query(cmd_sql)
@@ -2452,8 +2611,7 @@ def fullSync(version=''):
if args['begin'] == '1':
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
getPluginDir() + \
'/index.py do_full_sync {"db":"' + \
args['db'] + '","sign":"' + sign + '"} &'
'/index.py do_full_sync {"db":"' + args['db'] + '","sign":"' + sign + '"} &'
# print(cmd)
mw.execShell(cmd)
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
@@ -2475,6 +2633,7 @@ def fullSync(version=''):
return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
# python3 plugins/mariadb/index.py do_full_sync {"db":"demo1","sign":"","beigin":"1"}
def doFullSync(version=''):
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
@@ -2512,13 +2671,16 @@ def doFullSyncUser(version=''):
ip = data['ip']
bak_file = '/tmp/tmp.sql'
if os.path.exists(bak_file):
os.system("rm -rf " + bak_file)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 10})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
# https://mariadb.com/kb/zh-cn/mariadb-dump/
dump_sql_data = getServerDir() + "/bin/mariadb-dump -f --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p'" + apass + "' " + sync_db + ">" + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
@@ -2526,8 +2688,9 @@ def doFullSyncUser(version=''):
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db + ' < ' + bak_file
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db + '<' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
pinfo = parseSlaveSyncCmd(data['cmd'])
@@ -2729,6 +2892,8 @@ if __name__ == "__main__":
print(getConf())
elif func == 'bin_log':
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':
@@ -2797,6 +2962,8 @@ if __name__ == "__main__":
print(getDbrunMode(version))
elif func == 'set_dbrun_mode':
print(setDbrunMode(version))
elif func == 'reset_master':
print(resetMaster(version))
elif func == 'get_masterdb_list':
print(getMasterDbList(version))
elif func == 'get_master_status':
@@ -2821,6 +2988,8 @@ if __name__ == "__main__":
print(getMasterRepSlaveUserCmd(version))
elif func == 'get_slave_list':
print(getSlaveList(version))
elif func == 'try_slave_sync_bugfix':
print(trySlaveSyncBugfix(version))
elif func == 'get_slave_sync_cmd':
print(getSlaveSyncCmd(version))
elif func == 'get_slave_ssh_list':
+186
View File
@@ -0,0 +1,186 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import re
import json
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 'mariadb'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getSPluginDir():
return '/www/server/mdserver-web/plugins/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConf():
path = getServerDir() + '/etc/my.cnf'
return path
def getDataDir():
file = getConf()
content = mw.readFile(file)
rep = 'datadir\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getRelayLogName():
file = getConf()
content = mw.readFile(file)
rep = 'relay-log\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def binLogListLook(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListLookDecode(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceRelay(args):
rdata = {}
file = args['file']
line = args['line']
relay_name = getRelayLogName()
data_dir = getDataDir()
alist = os.listdir(data_dir)
relay_list = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(relay_name) and not f.endswith('.index'):
relay_list.append(f)
relay_list = sorted(relay_list, reverse=True)
if len(relay_list) == 0:
rdata['cmd'] = ''
rdata['data'] = '无Relay日志'
return rdata
file = relay_list[0]
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceBinLog(args):
rdata = {}
file = args['file']
line = args['line']
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
log_bin_l.append(f)
if len(log_bin_l) == 0:
rdata['cmd'] = ''
rdata['data'] = '无BINLOG'
return rdata
log_bin_l = sorted(log_bin_l, reverse=True)
file = log_bin_l[0]
my_bin = getServerDir() + '/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
+269 -10
View File
@@ -58,6 +58,62 @@ function myAsyncPost(method,args){
return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
}
function myPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'mariadb';
req_data['func'] = method;
req_data['script']='index_mariadb';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, 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 myPostCallbakN(method, version, args,callback){
var req_data = {};
req_data['name'] = 'mariadb';
req_data['func'] = method;
req_data['script']='index_mariadb';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function runInfo(){
myPost('run_info','',function(data){
@@ -83,7 +139,7 @@ function runInfo(){
<tr><th>活动/峰值连接数</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">若值过大,增加max_connections</td></tr>\
<tr><th>线程缓存命中率</th><td>' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加thread_cache_size</td></tr>\
<tr><th>索引命中率</th><td>' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加key_buffer_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + (rdata.Innodb_buffer_pool_read_requests / (rdata.Innodb_buffer_pool_read_requests+rdata.Innodb_buffer_pool_reads)).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
<tr><th>查询缓存命中率</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>创建临时表到磁盘</th><td>' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '%</td><td colspan="2">若过大,尝试增加tmp_table_size</td></tr>\
<tr><th>已打开的表</th><td>' + rdata.Open_tables + '</td><td colspan="2">若过大,增加table_cache_size</td></tr>\
@@ -438,13 +494,24 @@ function syncToDatabase(type){
}
function setRootPwd(type, pwd){
if (type==1){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
dbList();
},{icon: rdata.status ? 1 : 2});
});
return;
}
var index = layer.open({
type: 1,
area: '500px',
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交","关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@@ -454,16 +521,36 @@ function setRootPwd(type, pwd){
</div>\
</div>\
</form>",
yes:function(index,layero){
yes:function(layerIndex){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
layer.close(index);
},{icon: rdata.status ? 1 : 2});
});
return;
},
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@@ -1160,6 +1247,146 @@ function dbList(page, search){
});
}
function myBinRollingLogs(_name, func, _args, line){
var file_line = 100;
if ( typeof(line) != 'undefined' ){
file_line = line;
}
var reqTimer = null;
function requestLogs(func,file,line){
myPostCallbakN(func,'',{'file':file,"line":line}, function(rdata){
var data = rdata.data.data;
var cmd = rdata.data.cmd;
if(data == '') {
data = '当前没有日志!';
}
$('#my_rolling_cmd').html(cmd);
$('#my_rolling_copy').click(function(){
copyText(cmd);
});
var ebody = '<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log">'+data+'</textarea>';
$("#my_rolling_logs").html(ebody);
var ob = document.getElementById('roll_info_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: _name + '日志',
area: ['800px','700px'],
end: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
content:'<div class="change-default" style="padding:0px 20px 0px;">\
<div class="divtable mtb10">\
<table class="table table-hover"><tr>\
<td id="my_rolling_cmd">cmd</td>\
<td id="my_rolling_copy" style="width:35px;"><span class="ico-copy cursor btcopy" title="复制密码"></span></td>\
<tr>\
</table>\
</div>\
</div>\
<div class="change-default" style="padding:0px 20px 0px;" id="my_rolling_logs">\
<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log"></textarea>\
</div>',
success:function(){
var fileName = _args['file'];
requestLogs(func,fileName,file_line);
reqTimer = setInterval(function(){
requestLogs(func,fileName,file_line);
},1000);
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
_data['tojs'] = 'myBinLogsRender';
myPost('binlog_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var list = '';
for(i in rdata.data){
list += '<tr>';
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td>' + toSize(rdata.data[i]['size'])+'</td>';
list += '<td>' + rdata.data[i]['time'] +'</td>';
list += '<td style="text-align:right">';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look" class="btlink">查看</a> | ';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look_decode" class="btlink">解码查看</a>';
list += '</td></tr>';
}
if (rdata.data.length ==0){
list = '<tr><td colspan="4">无数据</td</tr>';
}
$("#binlog_list tbody").html(list);
$('#binlog_page').html(rdata.page);
$('#binlog_list .look').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看BINLOG','binLogListLook',{'file':file },100);
});
$('#binlog_list .look_decode').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看解码BINLOG','binLogListLookDecode',{'file':file },100);
});
});
}
function myBinLogs(){
var con = '<div class="safe bgw">\
<button class="btn btn-success btn-sm relay_trace" type="button" style="margin-right: 5px;">中继日志跟踪</button>\
<button class="btn btn-default btn-sm binlog_trace" type="button" style="margin-right: 5px;">最新BINLOG日志跟踪</button>\
<div id="binlog_list" class="divtable mtb10">\
<div class="tablescroll">\
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>文件名称</th>\
<th>大小</th>\
<th>时间</th>\
<th style="text-align:right;">操作</th>\
</tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="binlog_page" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
myBinLogsRender(1);
$('.soft-man-con .relay_trace').click(function(){
myBinRollingLogs('中继日志跟踪','binLogListTraceRelay',{'file':''},100);
});
$('.soft-man-con .binlog_trace').click(function(){
myBinRollingLogs('最新BINLOG日志跟踪','binLogListTraceBinLog',{'file':''},100);
});
}
function myLogs(){
@@ -1603,6 +1830,14 @@ function setDbMasterAccess(username){
});
}
function resetMaster(){
myPost('reset_master', '', function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
},{icon: rdata.status ? 1 : 2});
},'正在执行重置master命令[reset master]');
}
function getMasterRepSlaveList(){
var _data = {};
if (typeof(page) =='undefined'){
@@ -2329,11 +2564,16 @@ function masterOrSlaveConf(version=''){
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
</tr>";
var btn_list = ['复制错误',"取消"];
if (info['Last_IO_Error'].search(/1236/i)>0){
btn_list = ['复制错误',"取消","尝试修复"];
}
layer.open({
type: 1,
title: '同步异常信息',
area: ['600px','300px'],
btn:['复制错误',"取消"],
btn:btn_list,
content:"<form class='bt-form pd15'>\
<div class='divtable mtb10'>\
<div class='tablescroll'>\
@@ -2348,10 +2588,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@@ -2368,6 +2618,14 @@ function masterOrSlaveConf(version=''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
btn3:function(){
myPost('try_slave_sync_bugfix', {}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){
masterOrSlaveConf();
},{ icon: rdata.status ? 1 : 5 },2000);
});
}
});
});
@@ -2437,6 +2695,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Master[主]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.status ? 'btn-danger' : 'btn-success')+' btn-xs btn-master">'+(!rdata.status ? '未开启' : '已开启') +'</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()">重置</button>\
</p>\
<hr/>\
<!-- master list -->\
+1 -1
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.11.2
MY_VER=10.11.6
Install_app()
{
+1 -1
View File
@@ -13,7 +13,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.6.12
MY_VER=10.6.16
Install_app()
{
+1 -1
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.9.5
MY_VER=10.9.8
Install_app()
{
+2 -2
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.0.3
MY_VER=11.0.4
Install_app()
{
@@ -100,7 +100,7 @@ Install_app()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '11.0' > $serverPath/mariadb/version.pl
echo '安装完成'
else
echo '安装失败'
+2 -2
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.1.2
MY_VER=11.1.3
Install_app()
{
@@ -100,7 +100,7 @@ Install_app()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '11.1' > $serverPath/mariadb/version.pl
echo '安装完成'
else
echo '安装失败'
+2 -2
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.2.1
MY_VER=11.2.2
Install_app()
{
@@ -100,7 +100,7 @@ Install_app()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '11.2' > $serverPath/mariadb/version.pl
echo '安装完成'
else
echo '安装失败'
+2 -2
View File
@@ -14,7 +14,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.3.0
MY_VER=11.3.1
Install_app()
{
@@ -100,7 +100,7 @@ Install_app()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '11.3' > $serverPath/mariadb/version.pl
echo '安装完成'
else
echo '安装失败'
+5
View File
@@ -5,8 +5,13 @@ bind_ip = 127.0.0.1
port = 27017
fork = true
auth = false
#smallfiles = true
oplogSize=100
# Master/slave replication is no longer supported
#master = true
#replSet = test
pidfilepath = {$SERVER_PATH}/mongodb/mongodb.pid
+17 -5
View File
@@ -1,3 +1,14 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
@@ -5,19 +16,20 @@
<p onclick="pluginInitD('mongodb');">自启动</p>
<p onclick="pluginConfig('mongodb');">配置修改</p>
<p onclick="mongoStatus();">负载状态</p>
<p onclick="mongoDocStatus();">文档状态</p>
<p onclick="mongoReplStatus();">复制状态</p>
<p onclick="pluginLogs('mongodb','','run_log');">日志</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
<div class="soft-man-con" style="height:455px;overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
//mongodb start
var loading = layer.msg("资源加载中...", { icon: 16, time: 0, shade: 0.3 });
$.getScript( "/plugins/file?name=mongodb&f=js/mongodb.js", function(){
layer.close(loading);
pluginService('mongodb')
resetPluginWinHeight(530);
$.getScript('/plugins/file?name=mongodb&f=js/mongodb.js', function(){
pluginService('mongodb');
});
//mongodb end
</script>
+136 -15
View File
@@ -4,6 +4,9 @@ import sys
import io
import os
import time
import re
import json
import datetime
sys.path.append(os.getcwd() + "/class/core")
import mw
@@ -49,6 +52,13 @@ def getInitDTpl():
return path
def getConfPort():
file = getConf()
content = mw.readFile(file)
rep = 'port\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getArgs():
args = sys.argv[2:]
tmp = {}
@@ -68,7 +78,7 @@ def getArgs():
def status():
data = mw.execShell(
"ps -ef|grep mongod |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
"ps -ef|grep mongod |grep -v grep | grep -v /Applications | grep -v python | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
@@ -93,6 +103,11 @@ def initDreplace():
if not os.path.exists(data_dir):
os.mkdir(data_dir)
install_ok = getServerDir() + "/install.lock"
if os.path.exists(install_ok):
return file_bin
mw.writeFile(install_ok, 'ok')
# initd replace
content = mw.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path)
@@ -122,6 +137,7 @@ def mgOp(method):
file = initDreplace()
if mw.isAppleSystem():
data = mw.execShell(file + ' ' + method)
# print(data)
if data[1] == '':
return 'ok'
return data[1]
@@ -155,35 +171,134 @@ def restart():
def runInfo():
import pymongo
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
port = getConfPort()
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
db = client.admin
serverStatus = db.command('serverStatus')
listDbs = client.list_database_names()
result = {}
result["host"] = serverStatus['host']
result["version"] = serverStatus['version']
result["uptime"] = serverStatus['uptime']
result['db_path'] = getServerDir() + "/data"
result["connections"] = serverStatus['connections']['current']
result["collections"] = len(listDbs)
pf = serverStatus['opcounters']
result['pf'] = pf
return mw.getJson(result)
def runDocInfo():
import pymongo
port = getConfPort()
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
db = client.admin
serverStatus = db.command('serverStatus')
listDbs = client.list_database_names()
showDbList = []
result = {}
for x in range(len(listDbs)):
mongd = client[listDbs[x]]
stats = mongd.command({"dbstats": 1})
if 'operationTime' in stats:
del stats['operationTime']
if '$clusterTime' in stats:
del stats['$clusterTime']
showDbList.append(stats)
# print(showDbList)
# print(serverStatus)
# for key, value in serverStatus.items():
# print(key, value)
result = {}
result["version"] = serverStatus['version']
result["uptime"] = serverStatus['uptime']
result['db_path'] = getServerDir() + "/data"
result["connections"] = serverStatus['connections']['current']
if 'catalogStats' in serverStatus:
result["collections"] = serverStatus['catalogStats']['collections']
result["dbs"] = showDbList
return mw.getJson(result)
def runReplInfo():
import pymongo
port = getConfPort()
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
db = client.admin
serverStatus = db.command('serverStatus')
result = {}
result['status'] = '无'
result['doc_name'] = '无'
if 'repl' in serverStatus:
repl = serverStatus['repl']
# print(repl)
if 'ismaster' in repl and repl['ismaster']:
result['status'] = '主'
else:
result['status'] = '从'
result['setName'] = repl['setName']
result['primary'] = repl['primary']
result['me'] = repl['me']
hosts = repl['hosts']
result['hosts'] = ','.join(hosts)
return mw.returnJson(True, 'OK', result)
def test():
# https://pymongo.readthedocs.io/en/stable/examples/high_availability.html
import pymongo
from pymongo import ReadPreference
port = getConfPort()
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
db = client.admin
# config = {
# '_id': 'test',
# 'members': [
# {'_id': 1, 'host': '127.0.0.1:27018','priority': 10 },
# {'_id': 2, 'host': '127.0.0.1:27019','priority': 1 },
# {'_id': 3, 'host': '127.0.0.1:27020','priority': 0 },
# # {'_id': 2, 'host': 'localhost:27019'}
# ]
# }
# rsStatus = client.admin.command("replSetInitiate", config)
# 需要通过命令行操作
# -> rs.initiate({
# _id: 'test',
# members: [{
# _id: 1,
# host: '127.0.0.1:27018',
# priority: 2 // 这个priority不设置为1,值越高,当主库故障的时候会优先被选举成主库
# }, {
# _id: 2,
# host: '127.0.0.1:27019',
# priority: 0 //设置为0则不能成为主库
# }, {
# _id: 3,
# host: '127.0.0.1:27020',
# priority: 1
# }]
# });
# > rs.status(); // 查询状态
# // "stateStr" : "PRIMARY", 主节点
# // "stateStr" : "SECONDARY", 副本节点
# > rs.add({"_id":3, "host":"127.0.0.1:27318","priority":0,"votes":0});
serverStatus = db.command('serverStatus')
print(serverStatus)
# return mw.returnJson(True, 'OK', result)
def initdStatus():
if mw.isAppleSystem():
return "Apple Computer does not support"
@@ -266,9 +381,15 @@ if __name__ == "__main__":
print(initdUinstall())
elif func == 'run_info':
print(runInfo())
elif func == 'run_doc_info':
print(runDocInfo())
elif func == 'run_repl_info':
print(runReplInfo())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'test':
print(test())
else:
print('error')
+69 -6
View File
@@ -8,18 +8,40 @@ function mongoStatus() {
}
var rdata = $.parseJSON(data.data);
hit = (parseInt(rdata.keyspace_hits) / (parseInt(rdata.keyspace_hits) + parseInt(rdata.keyspace_misses)) * 100).toFixed(2);
var Con = '<div class="divtable">\
var con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
<tbody>\
<tr><th>host</th><td>' + rdata.host + '</td><td>服务器</td></tr>\
<tr><th>version</th><td>' + rdata.version + '</td><td>版本</td></tr>\
<tr><th>db_path</th><td>' + rdata.db_path + '</td><td>数据路径</td></tr>\
<tr><th>uptime</th><td>' + rdata.uptime + '</td><td>已运行秒</td></tr>\
<tr><th>connections</th><td>' + rdata.connections + '</td><td>当前链接数</td></tr>\
<tr><th>collections</th><td>' + rdata.collections + '</td><td>文档数</td></tr>\
<tr><th>insert</th><td>' + rdata.pf['insert'] + '</td><td>插入命令数</td></tr>\
<tr><th>query</th><td>' + rdata.pf['query'] + '</td><td>查询命令数</td></tr>\
<tr><th>update</th><td>' + rdata.pf['update'] + '</td><td>更新命令数</td></tr>\
<tr><th>delete</th><td>' + rdata.pf['delete'] + '</td><td>删除命令数</td></tr>\
<tr><th>getmore</th><td>' + rdata.pf['getmore'] + '</td><td>getmore命令数</td></tr>\
<tr><th>command</th><td>' + rdata.pf['command'] + '</td><td>执行命令数</td></tr>\
<tbody>\
</table></div><hr/>';
</table></div>';
$(".soft-man-con").html(con);
},'json');
}
function mongoDocStatus() {
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'mongodb', func:'run_doc_info'}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var rdata = $.parseJSON(data.data);
var t = '';
for(var i=0; i<rdata.dbs.length;i++){
@@ -35,13 +57,54 @@ function mongoStatus() {
}
// console.log(t);
Con += '<div class="divtable">\
var con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
<thead><th>库名</th><th>大小</th><th>存储大小</th><th>数据</th><th>索引</th><th>文档数据</th><th>对象</th></thead>\
<tbody>'+t+'<tbody>\
</table></div>';
// console.log(rdata.dbs);
$(".soft-man-con").html(Con);
$(".soft-man-con").html(con);
},'json');
}
}
function mongoReplStatus() {
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'mongodb', func:'run_repl_info'}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var rdata = $.parseJSON(data.data);
var rdata = rdata.data;
var tbody = '';
if (rdata.status == '无'){
tbody += '<tr><td colspan="3" style="text-align:center;">无数据</td></tr>';
} else{
tbody += '<tr><th>状态</th><td>' + rdata.status + '</td><td>主/从</td></tr>\
<tr><th>同步文档</th><td>' + rdata.setName + '</td><td>文档名</td></tr>\
<tr><th>hosts</th><td><span class="overflow_hide" style="width:260px;" title="'+rdata.hosts+'">' + rdata.hosts + '</span></td><td>服务器所有节点</td></tr>\
<tr><th>primary</th><td>' + rdata.primary + '</td><td>primary</td></tr>\
<tr><th>me</th><td>' + rdata.me + '</td><td>me</td></tr>';
}
var con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
<tbody>\
'+tbody+'\
<tbody>\
</table>\
</div>';
$(".soft-man-con").html(con);
},'json');
}
+108
View File
@@ -0,0 +1,108 @@
[client]
user = root
#password = your_password
port = 33206
socket = {$SERVER_APP_PATH}/mysql.sock
default-character-set = UTF8MB4
[mysqld]
!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
authentication_policy=mysql_native_password
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 33206
mysqlx_port = 33260
socket = {$SERVER_APP_PATH}/mysql.sock
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
server-id = {$SERVER_ID}
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
default_storage_engine = InnoDB
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=1
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
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
#sync_binlog=1
#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
slave_skip_errors=1062,1396
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
master_info_repository = table
relay_log_info_repository = table
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_redo_log_capacity=10485760
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
+1
View File
@@ -12,6 +12,7 @@
<p onclick="myPerfOpt();">性能优化</p>
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mysql-apt',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="myBinLogs();">BINLOG</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
+218 -4
View File
@@ -114,7 +114,16 @@ def getErrorLogsFile():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getAuthPolicy():
file = getConf()
content = mw.readFile(file)
rep = 'authentication_policy\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0].strip()
# caching_sha2_password
return 'mysql_native_password'
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
@@ -242,6 +251,12 @@ def getDataDir():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getPidFile():
file = getConf()
@@ -297,6 +312,58 @@ def setSkipGrantTables(v):
mw.writeFile(conf, con)
return True
def binLogList():
args = getArgs()
data = checkArgs(args, ['page', 'page_size', 'tojs'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
abspath = data_dir + '/' + f
t['name'] = f
t['size'] = os.path.getsize(abspath)
t['time'] = mw.getDataFromInt(os.path.getctime(abspath))
log_bin_l.append(t)
log_bin_l = sorted(log_bin_l, key=lambda x: x['time'], reverse=True)
# print(log_bin_l)
# print(data_dir, log_bin_name)
count = len(log_bin_l)
page_start = (page - 1) * page_size
page_end = page_start + page_size
if page_end > count:
page_end = count
data = {}
page_args = {}
page_args['count'] = count
page_args['p'] = page
page_args['row'] = page_size
page_args['tojs'] = args['tojs']
data['page'] = mw.getPage(page_args)
data['data'] = log_bin_l[page_start:page_end]
return mw.getJson(data)
def cleanBinLog():
db = pMysqlDb()
cleanTime = time.strftime('%Y-%m-%d %H:%i:%s', time.localtime())
db.execute("PURGE MASTER LOGS BEFORE '" + cleanTime + "';")
return mw.returnJson(True, '清理BINLOG成功!')
def getErrorLog():
args = getArgs()
@@ -1061,12 +1128,20 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb()
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
if version.find('5.7') > -1 or version.find('8.0') > -1:
@@ -1081,11 +1156,14 @@ def setRootPwd(version=''):
"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密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!'+msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
def setUserPwd(version=''):
args = getArgs()
data = checkArgs(args, ['password', 'name'])
@@ -1291,7 +1369,58 @@ def setDbAccess():
return mw.returnJson(True, '设置成功!')
def fixDbAccess(version):
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
if float(version) < 5.7:
cmd_pass = serverdir + '/bin/usr/bin/mysql --defaults-file=' + myconf + ' -uroot -e'
cmd_pass = cmd_pass + '"UPDATE mysql.user SET password=PASSWORD(\'' + pwd + "') WHERE user='root';"
cmd_pass = cmd_pass + 'flush privileges;"'
data = mw.execShell(cmd_pass)
# print(data)
else:
auth_policy = getAuthPolicy()
reset_pwd = 'flush privileges;'
reset_pwd = reset_pwd + \
"UPDATE mysql.user SET authentication_string='' WHERE user='root';"
reset_pwd = reset_pwd + "flush privileges;"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED by '" + pwd + "';"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
reset_pwd = reset_pwd + "flush privileges;"
tmp_file = "/tmp/mysql_init_tmp.log"
mw.writeFile(tmp_file, reset_pwd)
cmd_pass = serverdir + '/bin/usr/bin/mysql --defaults-file=' + myconf + ' -uroot -proot < ' + tmp_file
data = mw.execShell(cmd_pass)
# print(data)
os.remove(tmp_file)
return True
def fixDbAccess2(version):
try:
pdb = pMysqlDb()
data = pdb.query('show databases')
@@ -1304,6 +1433,35 @@ def fixDbAccess(version):
return mw.returnJson(True, '正常无需修复!')
except Exception as e:
return mw.returnJson(False, '修复失败请重试!')
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
openSkipGrantTables()
appCMD(version, 'start')
time.sleep(3)
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
except Exception as e:
return mw.returnJson(False, '修复失败请重试!')
def setDbRw(version=''):
@@ -2217,6 +2375,56 @@ def getSlaveList(version=''):
data['data'] = dlist
return mw.getJson(data)
def trySlaveSyncBugfix(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode != 'sync-user':
return mw.returnJson(False, '仅支持【同步账户】模式')
conn = pSqliteDb('slave_sync_user')
slave_sync_data = conn.field('ip,port,user,pass,mode,cmd').select()
if len(slave_sync_data) < 1:
return mw.returnJson(False, '需要先添加【同步用户】配置!')
# print(slave_sync_data)
# 本地从库
sdb = pMysqlDb()
gtid_purged = ''
for i in range(len(slave_sync_data)):
port = slave_sync_data[i]['port']
password = slave_sync_data[i]['pass']
host = slave_sync_data[i]['ip']
user = slave_sync_data[i]['user']
# print(port, password, host)
mdb = mw.getMyORM()
mdb.setHost(host)
mdb.setPort(port)
mdb.setUser(user)
mdb.setPwd(password)
mdb.setSocket('')
var_gtid = mdb.query('show VARIABLES like "%gtid_purged%"')
if len(var_gtid) > 0:
gtid_purged += var_gtid[0]['Value'] + ','
gtid_purged = gtid_purged.strip(',')
sql = "set @@global.gtid_purged='" + gtid_purged + "'"
sdb.query('stop slave')
# print(sql)
sdb.query(sql)
sdb.query('start slave')
return mw.returnJson(True, '修复成功!')
def getSlaveSyncCmd(version=''):
@@ -2802,6 +3010,8 @@ if __name__ == "__main__":
print(getConf())
elif func == 'bin_log':
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':
@@ -2852,6 +3062,8 @@ if __name__ == "__main__":
print(setDbAccess())
elif func == 'fix_db_access':
print(fixDbAccess(version))
elif func == 'fix_db_access2':
print(fixDbAccess2(version))
elif func == 'set_db_rw':
print(setDbRw(version))
elif func == 'set_db_ps':
@@ -2896,6 +3108,8 @@ if __name__ == "__main__":
print(getMasterRepSlaveUserCmd(version))
elif func == 'get_slave_list':
print(getSlaveList(version))
elif func == 'try_slave_sync_bugfix':
print(trySlaveSyncBugfix(version))
elif func == 'get_slave_sync_cmd':
print(getSlaveSyncCmd(version))
elif func == 'get_slave_ssh_list':
+186
View File
@@ -0,0 +1,186 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import re
import json
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()
def getSPluginDir():
return '/www/server/mdserver-web/plugins/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConf():
path = getServerDir() + '/etc/my.cnf'
return path
def getDataDir():
file = getConf()
content = mw.readFile(file)
rep = 'datadir\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getRelayLogName():
file = getConf()
content = mw.readFile(file)
rep = 'relay-log\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def binLogListLook(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListLookDecode(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceRelay(args):
rdata = {}
file = args['file']
line = args['line']
relay_name = getRelayLogName()
data_dir = getDataDir()
alist = os.listdir(data_dir)
relay_list = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(relay_name) and not f.endswith('.index'):
relay_list.append(f)
relay_list = sorted(relay_list, reverse=True)
if len(relay_list) == 0:
rdata['cmd'] = ''
rdata['data'] = '无Relay日志'
return rdata
file = relay_list[0]
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceBinLog(args):
rdata = {}
file = args['file']
line = args['line']
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
log_bin_l.append(f)
if len(log_bin_l) == 0:
rdata['cmd'] = ''
rdata['data'] = '无BINLOG'
return rdata
log_bin_l = sorted(log_bin_l, reverse=True)
file = log_bin_l[0]
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
+1 -1
View File
@@ -6,7 +6,7 @@
"type":"运行环境",
"ps":"一种关系数据库管理系统[debian,ubuntu](极速安装)",
"todo_versions":["5.7","8.0"],
"versions":["5.7","8.0"],
"versions":["5.7","8.0","8.2"],
"shell":"install.sh",
"install_pre_inspection":true,
"checks":"server/mysql-apt",
+254 -9
View File
@@ -59,6 +59,62 @@ function myAsyncPost(method,args){
return syncPost('/plugins/run', {name:'mysql-apt', func:method, args:_args});
}
function myPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'mysql';
req_data['func'] = method;
req_data['script']='index_mysql_apt';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, 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 myPostCallbakN(method, version, args,callback){
var req_data = {};
req_data['name'] = 'mysql';
req_data['func'] = method;
req_data['script']='index_mysql_apt';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function vaildPhpmyadmin(url,username,password){
// console.log("Authorization: Basic " + btoa(username + ":" + password));
$.ajax({
@@ -439,7 +495,6 @@ function setRootPwd(type, pwd){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
dbList();
$('.layui-layer-close1').click();
},{icon: rdata.status ? 1 : 2});
});
return;
@@ -451,7 +506,7 @@ function setRootPwd(type, pwd){
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交","关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@@ -461,8 +516,36 @@ function setRootPwd(type, pwd){
</div>\
</div>\
</form>",
yes:function(){
setRootPwd(1);
yes:function(layerIndex){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
},
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@@ -1162,6 +1245,146 @@ function dbList(page, search){
});
}
function myBinRollingLogs(_name, func, _args, line){
var file_line = 100;
if ( typeof(line) != 'undefined' ){
file_line = line;
}
var reqTimer = null;
function requestLogs(func,file,line){
myPostCallbakN(func,'',{'file':file,"line":line}, function(rdata){
var data = rdata.data.data;
var cmd = rdata.data.cmd;
if(data == '') {
data = '当前没有日志!';
}
$('#my_rolling_cmd').html(cmd);
$('#my_rolling_copy').click(function(){
copyText(cmd);
});
var ebody = '<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log">'+data+'</textarea>';
$("#my_rolling_logs").html(ebody);
var ob = document.getElementById('roll_info_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: _name + '日志',
area: ['800px','700px'],
end: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
content:'<div class="change-default" style="padding:0px 20px 0px;">\
<div class="divtable mtb10">\
<table class="table table-hover"><tr>\
<td id="my_rolling_cmd">cmd</td>\
<td id="my_rolling_copy" style="width:35px;"><span class="ico-copy cursor btcopy" title="复制密码"></span></td>\
<tr>\
</table>\
</div>\
</div>\
<div class="change-default" style="padding:0px 20px 0px;" id="my_rolling_logs">\
<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log"></textarea>\
</div>',
success:function(){
var fileName = _args['file'];
requestLogs(func,fileName,file_line);
reqTimer = setInterval(function(){
requestLogs(func,fileName,file_line);
},1000);
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
_data['tojs'] = 'myBinLogsRender';
myPost('binlog_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var list = '';
for(i in rdata.data){
list += '<tr>';
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td>' + toSize(rdata.data[i]['size'])+'</td>';
list += '<td>' + rdata.data[i]['time'] +'</td>';
list += '<td style="text-align:right">';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look" class="btlink">查看</a> | ';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look_decode" class="btlink">解码查看</a>';
list += '</td></tr>';
}
if (rdata.data.length ==0){
list = '<tr><td colspan="4">无数据</td</tr>';
}
$("#binlog_list tbody").html(list);
$('#binlog_page').html(rdata.page);
$('#binlog_list .look').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看BINLOG','binLogListLook',{'file':file },100);
});
$('#binlog_list .look_decode').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看解码BINLOG','binLogListLookDecode',{'file':file },100);
});
});
}
function myBinLogs(){
var con = '<div class="safe bgw">\
<button class="btn btn-success btn-sm relay_trace" type="button" style="margin-right: 5px;">中继日志跟踪</button>\
<button class="btn btn-default btn-sm binlog_trace" type="button" style="margin-right: 5px;">最新BINLOG日志跟踪</button>\
<div id="binlog_list" class="divtable mtb10">\
<div class="tablescroll">\
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>文件名称</th>\
<th>大小</th>\
<th>时间</th>\
<th style="text-align:right;">操作</th>\
</tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="binlog_page" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
myBinLogsRender(1);
$('.soft-man-con .relay_trace').click(function(){
myBinRollingLogs('中继日志跟踪','binLogListTraceRelay',{'file':''},100);
});
$('.soft-man-con .binlog_trace').click(function(){
myBinRollingLogs('最新BINLOG日志跟踪','binLogListTraceBinLog',{'file':''},100);
});
}
function myLogs(){
@@ -2345,11 +2568,15 @@ function masterOrSlaveConf(version=''){
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
</tr>";
var btn_list = ['复制错误',"取消"];
if (info['Last_IO_Error'].search(/1236/i)>0){
btn_list = ['复制错误',"取消","尝试修复"];
}
layer.open({
type: 1,
title: '同步异常信息',
area: ['600px','300px'],
btn:['复制错误',"取消"],
btn:btn_list,
content:"<form class='bt-form pd15'>\
<div class='divtable mtb10'>\
<div class='tablescroll'>\
@@ -2364,10 +2591,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@@ -2384,6 +2621,14 @@ function masterOrSlaveConf(version=''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
btn3:function(){
myPost('try_slave_sync_bugfix', {}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){
masterOrSlaveConf();
},{ icon: rdata.status ? 1 : 5 },2000);
});
}
});
});
+140
View File
@@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export DEBIAN_FRONTEND=noninteractive
# https://downloads.mysql.com/archives/community/
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
myDir=${serverPath}/source/mysql-apt
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
# cd /www/server/mdserver-web/plugins/mysql-apt && bash install.sh install 8.0
# 暂时debian12没有标准版,先用11使用
if [ "$OSNAME" == 'debian' ] && [ "$VERSION_ID" == '12' ] ;then
echo "暂时不支持该${OSNAME}${VERSION_ID}" > $install_tmp
exit 1
fi
ARCH="amd64"
TMP_ARCH=`arch`
if [ "$TMP_ARCH" == "x86_64" ];then
ARCH="amd64"
elif [ "$TMP_ARCH" == "aarch64" ];then
ARCH="arm64"
else
ARCH="amd64"
fi
if [ "$ARCH" != "amd64" ];then
echo "暂时不支持该${ARCH}" > $install_tmp
exit 1
fi
MYSQL_VER=8.2.0
SUFFIX_NAME=${MYSQL_VER}-1${OSNAME}${VERSION_ID}_${ARCH}
# /lib/systemd/system/mysql.service
# /etc/mysql/my.cnf
APT_INSTALL()
{
########
mkdir -p $myDir
mkdir -p $serverPath/mysql-apt/bin
wget --no-check-certificate -O ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar https://cdn.mysql.com/archives/mysql-8.2/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
chmod +x ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
cd ${myDir} && tar vxf ${myDir}/mysql-server_${SUFFIX_NAME}.deb-bundle.tar
apt update -y
apt install -y libnuma1 libaio1 libmecab2
# 安装
dpkg -X mysql-common_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client-plugins_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client-core_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-client_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-client_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-server-core_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-community-server_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
dpkg -X mysql-server_${SUFFIX_NAME}.deb $serverPath/mysql-apt/bin
# 测试时可关闭
rm -rf $myDir
#######
}
APT_UNINSTALL()
{
###
rm -rf $myDir
# apt remove -y mysql-server
###
}
Install_mysql()
{
echo '正在安装脚本文件...' > $install_tmp
if id mysql &> /dev/null ;then
echo "mysql uid is `id -u mysql`"
echo "mysql shell is `grep "^mysql:" /etc/passwd |cut -d':' -f7 `"
else
groupadd mysql
useradd -g mysql mysql
fi
isApt=`which apt`
if [ "$isApt" != "" ];then
APT_INSTALL
fi
if [ "$?" == "0" ];then
mkdir -p $serverPath/mysql-apt
echo '8.0' > $serverPath/mysql-apt/version.pl
echo '安装完成' > $install_tmp
else
echo '8.0' > $serverPath/mysql-apt/version.pl
echo "暂时不支持该系统" > $install_tmp
fi
}
Uninstall_mysql()
{
isApt=`which apt`
if [ "$isApt" != "" ];then
APT_UNINSTALL
fi
rm -rf $serverPath/mysql-apt
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_mysql
else
Uninstall_mysql
fi
+1
View File
@@ -12,6 +12,7 @@
<p onclick="myPerfOpt();">性能优化</p>
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mysql-yum',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
<p onclick="myBinLogs();">BINLOG</p>
<p onclick="dbList()">管理列表</p>
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
+247 -16
View File
@@ -89,6 +89,12 @@ def getDataDir():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getPidFile():
file = getConf()
@@ -129,6 +135,15 @@ def getErrorLogsFile():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getAuthPolicy():
file = getConf()
content = mw.readFile(file)
rep = 'authentication_policy\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0].strip()
# caching_sha2_password
return 'mysql_native_password'
def contentReplace(content):
service_path = mw.getServerDir()
@@ -276,6 +291,52 @@ def binLog():
mw.writeFile(conf, con)
return mw.returnJson(True, '设置成功!')
def binLogList():
args = getArgs()
data = checkArgs(args, ['page', 'page_size', 'tojs'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
abspath = data_dir + '/' + f
t['name'] = f
t['size'] = os.path.getsize(abspath)
t['time'] = mw.getDataFromInt(os.path.getctime(abspath))
log_bin_l.append(t)
log_bin_l = sorted(log_bin_l, key=lambda x: x['time'], reverse=True)
# print(log_bin_l)
# print(data_dir, log_bin_name)
count = len(log_bin_l)
page_start = (page - 1) * page_size
page_end = page_start + page_size
if page_end > count:
page_end = count
data = {}
page_args = {}
page_args['count'] = count
page_args['p'] = page
page_args['row'] = page_size
page_args['tojs'] = args['tojs']
data['page'] = mw.getPage(page_args)
data['data'] = log_bin_l[page_start:page_end]
return mw.getJson(data)
def cleanBinLog():
db = pMysqlDb()
@@ -360,8 +421,28 @@ def initMysql8Data():
return False
return True
def getLib64Pos(name=''):
cmd = "ls /usr/lib64 | grep "+name+".so | cut -d \ -f 1 | awk 'END {print}'"
d = mw.execShell(cmd)
return '/usr/lib64/'+d[0]
def makeLib64SoftLink(name=''):
pos = getLib64Pos(name)
dst_file = '/usr/lib64/'+name+'.so.5'
if os.path.exists(dst_file):
return True
if os.path.exists(pos):
cmd = 'ln -s '+pos+' '+dst_file
mw.execShell(cmd)
return True
def yumLibFix():
makeLib64SoftLink('libncurses')
makeLib64SoftLink('libtinfo')
def initMysql8Pwd():
yumLibFix()
'''
/usr/bin/mysql --defaults-file=/www/server/mysql-apt/etc/my.cnf -uroot -e"UPDATE mysql.user SET password=PASSWORD('BhIroUczczNVaKvw') WHERE user='root';flush privileges;"
/usr/bin/mysql --defaults-file=/www/server/mysql-apt/etc/my.cnf -uroot -e"alter user 'root'@'localhost' identified by '123456';"
@@ -371,6 +452,7 @@ def initMysql8Pwd():
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
auth_policy = getAuthPolicy()
cmd_my = serverdir + '/bin/usr/bin/mysql'
@@ -378,16 +460,18 @@ def initMysql8Pwd():
cmd_pass = cmd_pass + \
'"alter user \'root\'@\'localhost\' identified by \'' + pwd + '\';'
cmd_pass = cmd_pass + \
"alter user 'root'@'localhost' IDENTIFIED WITH mysql_native_password by '" + pwd + "';"
"alter user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
cmd_pass = cmd_pass + 'flush privileges;"'
# print(cmd_pass)
data = mw.execShell(cmd_pass)
# print(data)
if data[1] != '':
print(data[1])
exit(-1)
# 删除空账户
drop_empty_user = cmd_my + ' --defaults-file=' + myconf + ' -uroot -p' + \
pwd + ' -e "use mysql;delete from user where USER=\'\'"'
mw.execShell(drop_empty_user)
# drop_empty_user = cmd_my + ' --defaults-file=' + myconf + ' -uroot -p' + \
# pwd + ' -e "use mysql;delete from user where USER=\'\'"'
# mw.execShell(drop_empty_user)
# 删除测试数据库
drop_test_db = cmd_my + ' --defaults-file=' + myconf + ' -uroot -p' + \
@@ -397,15 +481,15 @@ def initMysql8Pwd():
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
# 删除冗余账户
hostname = mw.execShell('hostname')[0].strip()
if hostname != 'localhost':
drop_hostname = cmd_my + ' --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
mw.execShell(drop_hostname)
# hostname = mw.execShell('hostname')[0].strip()
# if hostname != 'localhost':
# drop_hostname = cmd_my + ' --defaults-file=' + \
# myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
# mw.execShell(drop_hostname)
drop_root_hostname = cmd_my + ' --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
mw.execShell(drop_root_hostname)
# drop_root_hostname = cmd_my + ' --defaults-file=' + \
# myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
# mw.execShell(drop_root_hostname)
return True
@@ -1041,12 +1125,20 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb()
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
if version.find('5.7') > -1 or version.find('8.0') > -1:
@@ -1061,7 +1153,11 @@ def setRootPwd(version=''):
"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密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!'+msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
@@ -1270,8 +1366,57 @@ def setDbAccess():
psdb.where('username=?', (name,)).save('accept,rw', (access, 'rw',))
return mw.returnJson(True, '设置成功!')
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def fixDbAccess(version):
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
if float(version) < 5.7:
cmd_pass = serverdir + '/bin/usr/bin/mysql --defaults-file=' + myconf + ' -uroot -e'
cmd_pass = cmd_pass + '"UPDATE mysql.user SET password=PASSWORD(\'' + pwd + "') WHERE user='root';"
cmd_pass = cmd_pass + 'flush privileges;"'
data = mw.execShell(cmd_pass)
# print(data)
else:
auth_policy = getAuthPolicy()
reset_pwd = 'flush privileges;'
reset_pwd = reset_pwd + \
"UPDATE mysql.user SET authentication_string='' WHERE user='root';"
reset_pwd = reset_pwd + "flush privileges;"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED by '" + pwd + "';"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
reset_pwd = reset_pwd + "flush privileges;"
tmp_file = "/tmp/mysql_init_tmp.log"
mw.writeFile(tmp_file, reset_pwd)
cmd_pass = serverdir + '/bin/usr/bin/mysql --defaults-file=' + myconf + ' -uroot -proot < ' + tmp_file
data = mw.execShell(cmd_pass)
# print(data)
os.remove(tmp_file)
return True
def fixDbAccess2(version):
try:
pdb = pMysqlDb()
data = pdb.query('show databases')
@@ -1285,6 +1430,34 @@ def fixDbAccess(version):
except Exception as e:
return mw.returnJson(False, '修复失败请重试!')
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
openSkipGrantTables()
appCMD(version, 'start')
time.sleep(3)
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
except Exception as e:
return mw.returnJson(False, '修复失败请重试!')
def setDbRw(version=''):
args = getArgs()
@@ -1832,12 +2005,14 @@ def addMasterRepSlaveUser(version=''):
pdb = pMysqlDb()
psdb = pSqliteDb('master_replication_user')
auth_policy = getAuthPolicy()
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 + "';"
"' IDENTIFIED WITH "+auth_policy+" BY '" + password + "';"
pdb.execute(sql)
sql = "grant replication slave on *.* to '" + username + "'@'%';"
result = pdb.execute(sql)
@@ -2197,6 +2372,56 @@ def getSlaveList(version=''):
data['data'] = dlist
return mw.getJson(data)
def trySlaveSyncBugfix(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
mode = mw.readFile(mode_file)
if mode != 'sync-user':
return mw.returnJson(False, '仅支持【同步账户】模式')
conn = pSqliteDb('slave_sync_user')
slave_sync_data = conn.field('ip,port,user,pass,mode,cmd').select()
if len(slave_sync_data) < 1:
return mw.returnJson(False, '需要先添加【同步用户】配置!')
# print(slave_sync_data)
# 本地从库
sdb = pMysqlDb()
gtid_purged = ''
for i in range(len(slave_sync_data)):
port = slave_sync_data[i]['port']
password = slave_sync_data[i]['pass']
host = slave_sync_data[i]['ip']
user = slave_sync_data[i]['user']
# print(port, password, host)
mdb = mw.getMyORM()
mdb.setHost(host)
mdb.setPort(port)
mdb.setUser(user)
mdb.setPwd(password)
mdb.setSocket('')
var_gtid = mdb.query('show VARIABLES like "%gtid_purged%"')
if len(var_gtid) > 0:
gtid_purged += var_gtid[0]['Value'] + ','
gtid_purged = gtid_purged.strip(',')
sql = "set @@global.gtid_purged='" + gtid_purged + "'"
sdb.query('stop slave')
# print(sql)
sdb.query(sql)
sdb.query('start slave')
return mw.returnJson(True, '修复成功!')
def getSlaveSyncCmd(version=''):
@@ -2775,6 +3000,8 @@ if __name__ == "__main__":
print(getConf())
elif func == 'bin_log':
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':
@@ -2825,6 +3052,8 @@ if __name__ == "__main__":
print(setDbAccess())
elif func == 'fix_db_access':
print(fixDbAccess(version))
elif func == 'fix_db_access2':
print(fixDbAccess2(version))
elif func == 'set_db_rw':
print(setDbRw(version))
elif func == 'set_db_ps':
@@ -2869,6 +3098,8 @@ if __name__ == "__main__":
print(getMasterRepSlaveUserCmd(version))
elif func == 'get_slave_list':
print(getSlaveList(version))
elif func == 'try_slave_sync_bugfix':
print(trySlaveSyncBugfix(version))
elif func == 'get_slave_sync_cmd':
print(getSlaveSyncCmd(version))
elif func == 'get_slave_ssh_list':
+186
View File
@@ -0,0 +1,186 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import re
import json
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-yum'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getSPluginDir():
return '/www/server/mdserver-web/plugins/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConf():
path = getServerDir() + '/etc/my.cnf'
return path
def getDataDir():
file = getConf()
content = mw.readFile(file)
rep = 'datadir\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getRelayLogName():
file = getConf()
content = mw.readFile(file)
rep = 'relay-log\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getLogBinName():
file = getConf()
content = mw.readFile(file)
rep = 'log-bin\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def binLogListLook(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListLookDecode(args):
file = args['file']
line = args['line']
data_dir = getDataDir()
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata = {}
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceRelay(args):
rdata = {}
file = args['file']
line = args['line']
relay_name = getRelayLogName()
data_dir = getDataDir()
alist = os.listdir(data_dir)
relay_list = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(relay_name) and not f.endswith('.index'):
relay_list.append(f)
relay_list = sorted(relay_list, reverse=True)
if len(relay_list) == 0:
rdata['cmd'] = ''
rdata['data'] = '无Relay日志'
return rdata
file = relay_list[0]
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
def binLogListTraceBinLog(args):
rdata = {}
file = args['file']
line = args['line']
data_dir = getDataDir()
log_bin_name = getLogBinName()
alist = os.listdir(data_dir)
log_bin_l = []
for x in range(len(alist)):
f = alist[x]
t = {}
if f.startswith(log_bin_name) and not f.endswith('.index'):
log_bin_l.append(f)
if len(log_bin_l) == 0:
rdata['cmd'] = ''
rdata['data'] = '无BINLOG'
return rdata
log_bin_l = sorted(log_bin_l, reverse=True)
file = log_bin_l[0]
my_bin = getServerDir() + '/bin/usr/bin'
my_binlog_cmd = my_bin + '/mysqlbinlog'
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
data_dir + '/' + file + '|tail -' + str(line)
data = mw.execShell(cmd)
rdata['cmd'] = cmd
rdata['data'] = data[0]
return rdata
+255 -9
View File
@@ -59,6 +59,63 @@ function myAsyncPost(method,args){
return syncPost('/plugins/run', {name:'mysql-yum', func:method, args:_args});
}
function myPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'mysql-yum';
req_data['func'] = method;
req_data['script']='index_mysql_yum';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, 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 myPostCallbakN(method, version, args,callback){
var req_data = {};
req_data['name'] = 'mysql-yum';
req_data['func'] = method;
req_data['script']='index_mysql_yum';
args['version'] = version;
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function vaildPhpmyadmin(url,username,password){
// console.log("Authorization: Basic " + btoa(username + ":" + password));
$.ajax({
@@ -439,7 +496,6 @@ function setRootPwd(type, pwd){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
dbList();
$('.layui-layer-close1').click();
},{icon: rdata.status ? 1 : 2});
});
return;
@@ -451,7 +507,7 @@ function setRootPwd(type, pwd){
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交","关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@@ -461,8 +517,36 @@ function setRootPwd(type, pwd){
</div>\
</div>\
</form>",
yes:function(){
setRootPwd(1);
yes:function(layerIndex){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
},
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@@ -1162,6 +1246,146 @@ function dbList(page, search){
});
}
function myBinRollingLogs(_name, func, _args, line){
var file_line = 100;
if ( typeof(line) != 'undefined' ){
file_line = line;
}
var reqTimer = null;
function requestLogs(func,file,line){
myPostCallbakN(func,'',{'file':file,"line":line}, function(rdata){
var data = rdata.data.data;
var cmd = rdata.data.cmd;
if(data == '') {
data = '当前没有日志!';
}
$('#my_rolling_cmd').html(cmd);
$('#my_rolling_copy').click(function(){
copyText(cmd);
});
var ebody = '<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log">'+data+'</textarea>';
$("#my_rolling_logs").html(ebody);
var ob = document.getElementById('roll_info_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: _name + '日志',
area: ['800px','700px'],
end: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
content:'<div class="change-default" style="padding:0px 20px 0px;">\
<div class="divtable mtb10">\
<table class="table table-hover"><tr>\
<td id="my_rolling_cmd">cmd</td>\
<td id="my_rolling_copy" style="width:35px;"><span class="ico-copy cursor btcopy" title="复制密码"></span></td>\
<tr>\
</table>\
</div>\
</div>\
<div class="change-default" style="padding:0px 20px 0px;" id="my_rolling_logs">\
<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log"></textarea>\
</div>',
success:function(){
var fileName = _args['file'];
requestLogs(func,fileName,file_line);
reqTimer = setInterval(function(){
requestLogs(func,fileName,file_line);
},1000);
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
_data['tojs'] = 'myBinLogsRender';
myPost('binlog_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var list = '';
for(i in rdata.data){
list += '<tr>';
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td>' + toSize(rdata.data[i]['size'])+'</td>';
list += '<td>' + rdata.data[i]['time'] +'</td>';
list += '<td style="text-align:right">';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look" class="btlink">查看</a> | ';
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look_decode" class="btlink">解码查看</a>';
list += '</td></tr>';
}
if (rdata.data.length ==0){
list = '<tr><td colspan="4">无数据</td</tr>';
}
$("#binlog_list tbody").html(list);
$('#binlog_page').html(rdata.page);
$('#binlog_list .look').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看BINLOG','binLogListLook',{'file':file },100);
});
$('#binlog_list .look_decode').click(function(){
var i = $(this).data('index');
var file = rdata.data[i]['name'];
myBinRollingLogs('查看解码BINLOG','binLogListLookDecode',{'file':file },100);
});
});
}
function myBinLogs(){
var con = '<div class="safe bgw">\
<button class="btn btn-success btn-sm relay_trace" type="button" style="margin-right: 5px;">中继日志跟踪</button>\
<button class="btn btn-default btn-sm binlog_trace" type="button" style="margin-right: 5px;">最新BINLOG日志跟踪</button>\
<div id="binlog_list" class="divtable mtb10">\
<div class="tablescroll">\
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>文件名称</th>\
<th>大小</th>\
<th>时间</th>\
<th style="text-align:right;">操作</th>\
</tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="binlog_page" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
myBinLogsRender(1);
$('.soft-man-con .relay_trace').click(function(){
myBinRollingLogs('中继日志跟踪','binLogListTraceRelay',{'file':''},100);
});
$('.soft-man-con .binlog_trace').click(function(){
myBinRollingLogs('最新BINLOG日志跟踪','binLogListTraceBinLog',{'file':''},100);
});
}
function myLogs(){
@@ -2345,11 +2569,15 @@ function masterOrSlaveConf(version=''){
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
</tr>";
var btn_list = ['复制错误',"取消"];
if (info['Last_IO_Error'].search(/1236/i)>0){
btn_list = ['复制错误',"取消","尝试修复"];
}
layer.open({
type: 1,
title: '同步异常信息',
area: ['600px','300px'],
btn:['复制错误',"取消"],
btn:btn_list,
content:"<form class='bt-form pd15'>\
<div class='divtable mtb10'>\
<div class='tablescroll'>\
@@ -2364,10 +2592,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@@ -2384,6 +2622,14 @@ function masterOrSlaveConf(version=''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
btn3:function(){
myPost('try_slave_sync_bugfix', {}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){
masterOrSlaveConf();
},{ icon: rdata.status ? 1 : 5 },2000);
});
}
});
});
+2 -2
View File
@@ -100,7 +100,7 @@ Install_mysql()
rm -rf $myDir
echo '8.0' > $serverPath/mysql-yum/version.pl
echo '安装完成' > $install_tmp
echo '安装完成'
}
Uninstall_mysql()
@@ -110,7 +110,7 @@ Uninstall_mysql()
YUM_UNINSTALL
fi
rm -rf $serverPath/mysql-yum
echo '卸载完成' > $install_tmp
echo '卸载完成'
}
action=$1
+291
View File
@@ -0,0 +1,291 @@
# coding: utf-8
import re
import os
import sys
import pymysql.cursors
class ORM:
__DB_PASS = None
__DB_USER = 'root'
__DB_PORT = 3306
__DB_NAME = ''
__DB_HOST = 'localhost'
__DB_CONN = None
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
__DB_SOCKET = '/www/server/mysql/mysql.sock'
__DB_CHARSET = "utf8"
# orm
__DB_TABLE = "" # 被操作的表名称
__OPT_WHERE = "" # where条件
__OPT_LIMIT = "" # limit条件
__OPT_GROUP = "" # group条件
__OPT_ORDER = "" # order条件
__OPT_FIELD = "*" # field条件
__OPT_PARAM = () # where值
def __Conn(self):
'''连接数据库'''
try:
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,
database=self.__DB_NAME,
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,
database=self.__DB_NAME,
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,
database=self.__DB_NAME,
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,
database=self.__DB_NAME,
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
except Exception as e:
self.__DB_ERR = e
return False
def setDbConf(self, conf):
self.__DB_CNF = conf
def setSocket(self, sock):
self.__DB_SOCKET = sock
def setCharset(self, charset):
self.__DB_CHARSET = charset
def setHost(self, host):
self.__DB_HOST = host
def setPort(self, port):
self.__DB_PORT = port
def setUser(self, user):
self.__DB_USER = user
def setPwd(self, pwd):
self.__DB_PASS = pwd
def getPwd(self):
return self.__DB_PASS
def setDbName(self, name):
self.__DB_NAME = name
def execute(self, sql, param=()):
# 执行SQL语句返回受影响行
if not self.__Conn():
return self.__DB_ERR
try:
result = self.__DB_CUR.execute(sql,param)
self.__DB_CONN.commit()
self.__Close()
return result
except Exception as ex:
return ex
def query(self, sql, param=()):
# 执行SQL语句返回数据集
if not self.__Conn():
return self.__DB_ERR
try:
self.__DB_CUR.execute(sql,param)
result = self.__DB_CUR.fetchall()
# print(result)
# 将元组转换成列表
# data = map(list, result)
self.__Close()
return result
except Exception as ex:
return ex
def __Close(self):
# 关闭连接
self.__DB_CUR.close()
self.__DB_CONN.close()
def checkInput(self, data):
if not data:
return data
if type(data) != str:
return data
checkList = [
{'d': '<', 'r': '<'},
{'d': '>', 'r': '>'},
{'d': '\'', 'r': '‘'},
{'d': '"', 'r': '“'},
{'d': '&', 'r': '&'},
{'d': '#', 'r': '#'},
{'d': '<', 'r': '<'}
]
for v in checkList:
data = data.replace(v['d'], v['r'])
return data
def table(self, table):
# 设置表名
self.__DB_TABLE = table
return self
def where(self, where, param):
# WHERE条件
if where:
self.__OPT_WHERE = " WHERE " + where
self.__OPT_PARAM = param
return self
def andWhere(self, where, param):
# WHERE条件
if where:
self.__OPT_WHERE = self.__OPT_WHERE + " and " + where
# print(param)
# print(self.__OPT_PARAM)
self.__OPT_PARAM = self.__OPT_PARAM + param
return self
def order(self, order):
# ORDER条件
if len(order):
self.__OPT_ORDER = " ORDER BY " + order
else:
self.__OPT_ORDER = ""
return self
def group(self, group):
if len(group):
self.__OPT_GROUP = " GROUP BY " + group
else:
self.__OPT_GROUP = ""
return self
def limit(self, limit):
# LIMIT条件
if len(limit):
self.__OPT_LIMIT = " LIMIT " + limit
else:
self.__OPT_LIMIT = ""
return self
def field(self, field):
# FIELD条件
if len(field):
self.__OPT_FIELD = field
return self
def find(self):
# 取一行数据
result = self.limit("1").select()
# print(result)
if len(result) == 1:
return result[0]
return result
def select(self):
# 查询数据集
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
# print(sql)
# print(self.__OPT_PARAM)
result = self.query(sql, self.__OPT_PARAM)
return result
def getField(self, keyName):
# 取回指定字段
result = self.field(keyName).select()
# print(result[0][keyName])
if len(result) == 1:
return result[0][keyName]
return result
def setField(self, keyName, keyValue):
# 更新指定字段
return self.save(keyName, (keyValue,))
# 构造数据
def __format_pdata(self, pdata):
keys = pdata.keys()
keys_str = ','.join(keys)
param = []
for k in keys:
param.append(pdata[k])
return keys_str, tuple(param)
def delete(self, id=None):
# 删除数据
if id:
self.__OPT_WHERE = " WHERE id=%s"
self.__OPT_PARAM = (id,)
sql = "DELETE FROM " + self.__DB_TABLE + self.__OPT_WHERE
# print(sql)
result = self.execute(sql, self.__OPT_PARAM)
return result
def save(self, keys, param):
# 更新数据
opt = ""
for key in keys.split(','):
opt += key + "=%s,"
opt = opt[0:len(opt) - 1]
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt + self.__OPT_WHERE
# 处理拼接WHERE与UPDATE参数
tmp = list(param)
for arg in self.__OPT_PARAM:
tmp.append(arg)
self.__OPT_PARAM = tuple(tmp)
# print(sql,self.__OPT_PARAM)
result = self.execute(sql, self.__OPT_PARAM)
return result
# 更新数据
def update(self, pdata):
if not pdata:
return False
keys, param = self.__format_pdata(pdata)
return self.save(keys, param)
def add(self, keys, param):
# 插入数据
values = ""
for key in keys.split(','):
values += "%s,"
values = self.checkInput(values[0:len(values) - 1])
sql = "INSERT INTO " + self.__DB_TABLE + \
"(" + keys + ") " + "VALUES(" + values + ")"
# print(sql)
result = self.execute(sql, param)
return result
+2 -1
View File
@@ -1,4 +1,5 @@
[mysqld]
# SHOW GLOBAL VARIABLES LIKE '%gtid%'
gtid_mode=ON
enforce_gtid_consistency=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
+1 -4
View File
@@ -20,7 +20,7 @@ basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
server-id = {$SERVER_ID}
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
#sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
default_storage_engine = InnoDB
@@ -48,7 +48,6 @@ skip_name_resolve=1
#skip-grant-tables
log-bin=mysql-bin
binlog_format=mixed
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
long_query_time=10
@@ -84,8 +83,6 @@ replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
master_info_repository = table
relay_log_info_repository = table
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
+116
View File
@@ -0,0 +1,116 @@
[client]
user = root
#password = your_password
port = 3306
socket = {$SERVER_APP_PATH}/mysql.sock
default-character-set = UTF8MB4
[mysqld]
!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
sha256_password_private_key_path={$SERVER_APP_PATH}/data/mysql.pem
sha256_password_public_key_path={$SERVER_APP_PATH}/data/mysql.pub
authentication_policy=mysql_native_password
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
user = mysql
port = 3306
socket = {$SERVER_APP_PATH}/mysql.sock
basedir = {$SERVER_APP_PATH}
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
server-id = {$SERVER_ID}
#sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
default_storage_engine = InnoDB
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_name_resolve=1
#skip-networking
#skip-external-locking
#loose-skip-innodb
#skip-grant-tables
log-bin=mysql-bin
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
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
#多主设置
#auto_increment_offset=2
#auto_increment_increment=2
#master
#sync_binlog=1
#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 = 1
# Prevent replication from starting automatically with MySQL
#skip_replica_start = 1
#replicate-do-db
replica_skip_errors=1062,1396
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
replicate-ignore-db = test
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_redo_log_capacity=10485760
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
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
+143 -46
View File
@@ -116,6 +116,16 @@ def getErrorLogsFile():
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getAuthPolicy():
file = getConf()
content = mw.readFile(file)
rep = 'authentication_policy\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0].strip()
# caching_sha2_password
return 'mysql_native_password'
def getInitdTpl(version=''):
path = getPluginDir() + '/init.d/mysql' + version + '.tpl'
@@ -182,7 +192,11 @@ def pMysqlDb():
def makeInitRsaKey(version=''):
datadir = getServerDir() + "/data"
try:
datadir = getDataDir()
except Exception as e:
datadir = getServerDir() + "/data"
mysql_pem = datadir + "/mysql.pem"
if not os.path.exists(mysql_pem):
rdata = mw.execShell(
@@ -395,22 +409,6 @@ def cleanBinLog():
db.execute("PURGE MASTER LOGS BEFORE '" + cleanTime + "';")
return mw.returnJson(True, '清理BINLOG成功!')
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():
args = getArgs()
filename = getErrorLogsFile()
@@ -516,20 +514,22 @@ def initMysqlPwd():
hostname = mw.execShell('hostname')[0].strip()
if hostname != 'localhost':
drop_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
myconf + ' -uroot -p"' + pwd + '" -e "drop user \'\'@\'' + hostname + '\'";'
mw.execShell(drop_hostname)
drop_root_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
myconf + ' -uroot -p"' + pwd + '" -e "drop user \'root\'@\'' + hostname + '\'";'
mw.execShell(drop_root_hostname)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
return True
def initMysql8Pwd():
time.sleep(8)
auth_policy = getAuthPolicy()
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
@@ -543,7 +543,7 @@ def initMysql8Pwd():
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 user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
alter_root_pwd = alter_root_pwd + "flush privileges;"
cmd_pass = serverdir + '/bin/mysqladmin --defaults-file=' + \
@@ -562,7 +562,7 @@ def initMysql8Pwd():
# 删除测试数据库
drop_test_db = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop database test";'
myconf + ' -uroot -p"' + pwd + '" -e "drop database test";'
mw.execShell(drop_test_db)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
@@ -571,11 +571,11 @@ def initMysql8Pwd():
hostname = mw.execShell('hostname')[0].strip()
if hostname != 'localhost':
drop_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
myconf + ' -uroot -p"' + pwd + '" -e "drop user \'\'@\'' + hostname + '\'";'
mw.execShell(drop_hostname)
drop_root_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
myconf + ' -uroot -p"' + pwd + '" -e "drop user \'root\'@\'' + hostname + '\'";'
mw.execShell(drop_root_hostname)
return True
@@ -620,6 +620,8 @@ def my8cmd(version, method):
isInited = initMysql57Data()
elif version == '8.0':
isInited = initMysql8Data()
elif version == '8.2':
isInited = initMysql8Data()
if not isInited:
@@ -660,7 +662,7 @@ def my8cmd(version, method):
def appCMD(version, action):
makeInitRsaKey(version)
if version == '8.0' or version == '5.7':
if float(version) >= 5.7:
status = my8cmd(version, action)
else:
status = myOp(version, action)
@@ -792,7 +794,7 @@ def getMyPort():
return tmp.groups()[0].strip()
def setMyPort():
def setMyPort(version):
args = getArgs()
data = checkArgs(args, ['port'])
if not data[0]:
@@ -804,7 +806,7 @@ def setMyPort():
rep = "port\s*=\s*([0-9]+)\s*\n"
content = re.sub(rep, 'port = ' + port + '\n', content)
mw.writeFile(file, content)
restart()
restart(version)
return mw.returnJson(True, '编辑成功!')
@@ -1052,7 +1054,7 @@ def importDbExternal():
myPass(True, pwd)
mysql_cmd = getServerDir() + '/bin/mysql --defaults-file=' + my_cnf + \
' -uroot -p\"' + pwd + '\" -f ' + name + ' < ' + import_sql
' -uroot -p"' + pwd + '" -f ' + name + ' < ' + import_sql
# print(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
@@ -1090,8 +1092,8 @@ def importDbBackup():
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + name + ' < ' + file_path_sql
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p"' + pwd + \
'" ' + name + ' < ' + file_path_sql
# print(mysql_cmd)
# os.system(mysql_cmd)
@@ -1259,7 +1261,7 @@ def syncGetDatabases():
host = user["Host"]
break
ps = mw.getMsg('INPUT_PS')
ps = vdb_name
if vdb_name == 'test':
ps = mw.getMsg('DATABASE_TEST')
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
@@ -1331,12 +1333,20 @@ def setRootPwd(version=''):
if not data[0]:
return data[1]
#强制修改
force = 0
if 'force' in args and args['force'] == '1':
force = 1
password = args['password']
try:
pdb = pMysqlDb()
result = pdb.query("show databases")
isError = isSqlError(result)
if isError != None:
if force == 1:
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
return isError
if version.find('5.7') > -1 or version.find('8.0') > -1:
@@ -1351,7 +1361,12 @@ def setRootPwd(version=''):
"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密码修改成功!')
msg = ''
if force == 1:
msg = ',无须强制!'
return mw.returnJson(True, '数据库root密码修改成功!'+msg)
except Exception as ex:
return mw.returnJson(False, '修改错误:' + str(ex))
@@ -1561,15 +1576,79 @@ def setDbAccess():
return mw.returnJson(True, '设置成功!')
def openSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('#skip-grant-tables','skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def closeSkipGrantTables():
mycnf = getConf()
content = mw.readFile(mycnf)
content = content.replace('skip-grant-tables','#skip-grant-tables')
mw.writeFile(mycnf, content)
return True
def resetDbRootPwd(version):
serverdir = getServerDir()
myconf = serverdir + "/etc/my.cnf"
pwd = mw.getRandomString(16)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
if float(version) < 5.7:
cmd_pass = serverdir + '/bin/mysql --defaults-file=' + myconf + ' -uroot -e'
cmd_pass = cmd_pass + '"UPDATE mysql.user SET password=PASSWORD(\'' + pwd + "') WHERE user='root';"
cmd_pass = cmd_pass + 'flush privileges;"'
data = mw.execShell(cmd_pass)
# print(data)
else:
auth_policy = getAuthPolicy()
reset_pwd = 'flush privileges;'
reset_pwd = reset_pwd + \
"UPDATE mysql.user SET authentication_string='' WHERE user='root';"
reset_pwd = reset_pwd + "flush privileges;"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED by '" + pwd + "';"
reset_pwd = reset_pwd + \
"alter user 'root'@'localhost' IDENTIFIED WITH "+auth_policy+" by '" + pwd + "';"
reset_pwd = reset_pwd + "flush privileges;"
tmp_file = "/tmp/mysql_init_tmp.log"
mw.writeFile(tmp_file, reset_pwd)
cmd_pass = serverdir + '/bin/mysql --defaults-file=' + myconf + ' -uroot -proot < ' + tmp_file
data = mw.execShell(cmd_pass)
# print(data)
os.remove(tmp_file)
return True
def fixDbAccess(version):
pdb = pMysqlDb()
mdb_ddir = getDataDir()
if not os.path.exists(mdb_ddir):
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
try:
pdb = pMysqlDb()
data = pdb.query('show databases')
isError = isSqlError(data)
if isError != None:
# 重置密码
appCMD(version, 'stop')
mw.execShell("rm -rf " + getServerDir() + "/data")
openSkipGrantTables()
appCMD(version, 'start')
time.sleep(3)
resetDbRootPwd(version)
appCMD(version, 'stop')
closeSkipGrantTables()
appCMD(version, 'start')
return mw.returnJson(True, '修复成功!')
return mw.returnJson(True, '正常无需修复!')
except Exception as e:
@@ -2123,12 +2202,14 @@ def addMasterRepSlaveUser(version=''):
pdb = pMysqlDb()
psdb = pSqliteDb('master_replication_user')
auth_policy = getAuthPolicy()
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 + "';"
"' IDENTIFIED WITH "+auth_policy+" BY '" + password + "';"
pdb.execute(sql)
sql = "grant replication slave on *.* to '" + username + "'@'%';"
result = pdb.execute(sql)
@@ -2517,6 +2598,10 @@ def trySlaveSyncBugfix(version=''):
gtid_purged = ''
var_slave_gtid = sdb.query('show VARIABLES like "%gtid_purged%"')
if len(var_slave_gtid) > 0:
gtid_purged += var_slave_gtid[0]['Value'] + ','
for i in range(len(slave_sync_data)):
port = slave_sync_data[i]['port']
password = slave_sync_data[i]['pass']
@@ -2536,6 +2621,8 @@ def trySlaveSyncBugfix(version=''):
if len(var_gtid) > 0:
gtid_purged += var_gtid[0]['Value'] + ','
gtid_purged = gtid_purged.strip(',')
sql = "set @@global.gtid_purged='" + gtid_purged + "'"
@@ -2865,6 +2952,8 @@ def doFullSyncUser(version=''):
ip = data['ip']
bak_file = '/tmp/tmp.sql'
if os.path.exists(bak_file):
os.system("rm -rf " + bak_file)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
@@ -2872,22 +2961,32 @@ def doFullSyncUser(version=''):
if mode == 'gtid':
dmp_option = ' --set-gtid-purged=off '
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
time.sleep(1)
writeDbSyncStatus({'code': 1, 'msg': '正在停止从库...', 'progress': 15})
if version == '8.0':
db.query("stop slave user='{}' password='{}';".format(user, apass))
else:
db.query("stop slave")
time.sleep(2)
writeDbSyncStatus({'code': 2, 'msg': '远程导出数据...', 'progress': 20})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p\"" + apass + \
"\" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
# print(dump_sql_data)
port + " -u" + user + " -p'" + apass + \
"' --ssl-mode=DISABLED " + sync_db + " > " + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
writeDbSyncStatus({'code': 3, 'msg': '正在到本地导入数据中...', 'progress': 40})
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
' ' + sync_db_import + ' < ' + bak_file
# print(my_import_cmd)
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db_import + ' < ' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
if version == '8.0':
@@ -3133,8 +3232,6 @@ if __name__ == "__main__":
print(binLog())
elif func == 'binlog_list':
print(binLogList())
elif func == 'binlog_look':
print(binLogListLook())
elif func == 'clean_bin_log':
print(cleanBinLog())
elif func == 'error_log':
@@ -3148,7 +3245,7 @@ if __name__ == "__main__":
elif func == 'my_port':
print(getMyPort())
elif func == 'set_my_port':
print(setMyPort())
print(setMyPort(version))
elif func == 'init_pwd':
print(initMysqlPwd())
elif func == 'root_pwd':
+3 -3
View File
@@ -9,9 +9,9 @@
"uninstall_pre_inspection":true,
"checks": "server/mysql/VERSION/bin/mysql",
"path": "server/mysql/VERSION",
"todo_versions":["5.6","5.7","8.0"],
"versions":["5.5", "5.6", "5.7","8.0"],
"updates":["5.5.62","5.6.50", "5.7.32","8.0.34"],
"todo_versions":["5.6","5.7","8.0","8.2"],
"versions":["5.5", "5.6", "5.7","8.0","8.2"],
"updates":["5.5.62","5.6.50", "5.7.32","8.0.34","8.2.0"],
"shell":"install.sh",
"checks":"server/mysql",
"path":"server/mysql",
+3
View File
@@ -5,6 +5,9 @@ export PATH
# 手动主从设置
# https://www.cnblogs.com/whiteY/p/17331882.html
# cd /www/server/mdserver-web/plugins/mysql && bash install.sh install 8.2
# cd /www/server/mdserver-web && source bin/activate && python3 /www/server/mdserver-web/plugins/mysql/index.py try_slave_sync_bugfix {}
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
+52 -14
View File
@@ -161,7 +161,7 @@ function runInfo(){
<tr><th>活动/峰值连接数</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">若值过大,增加max_connections</td></tr>\
<tr><th>线程缓存命中率</th><td>' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加thread_cache_size</td></tr>\
<tr><th>索引命中率</th><td>' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加key_buffer_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
<tr><th>Innodb索引命中率</th><td>' + (rdata.Innodb_buffer_pool_read_requests / (rdata.Innodb_buffer_pool_read_requests+rdata.Innodb_buffer_pool_reads)).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
<tr><th>查询缓存命中率</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>创建临时表到磁盘</th><td>' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '%</td><td colspan="2">若过大,尝试增加tmp_table_size</td></tr>\
<tr><th>已打开的表</th><td>' + rdata.Open_tables + '</td><td colspan="2">若过大,增加table_cache_size</td></tr>\
@@ -200,7 +200,7 @@ function myPort(){
myPost('my_port','',function(data){
var con = '<div class="line ">\
<div class="info-r ml0">\
<input name="port" class="bt-input-text mr5 port" type="text" style="width:100px" value="'+data.data+'">\
<input name="port" class="bt-input-text mr5 port" type="number" style="width:100px" value="'+data.data+'">\
<button id="btn_change_port" name="btn_change_port" class="btn btn-success btn-sm mr5 ml5 btn_change_port">修改</button>\
</div></div>';
$(".soft-man-con").html(con);
@@ -496,7 +496,6 @@ function setRootPwd(type, pwd){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
dbList();
$('.layui-layer-close1').click();
},{icon: rdata.status ? 1 : 2});
});
return;
@@ -508,7 +507,7 @@ function setRootPwd(type, pwd){
title: '修改数据库密码',
closeBtn: 1,
shift: 5,
btn:["提交","关闭"],
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
shadeClose: true,
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
@@ -518,8 +517,36 @@ function setRootPwd(type, pwd){
</div>\
</div>\
</form>",
yes:function(){
setRootPwd(1);
yes:function(layerIndex){
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
},
btn3:function(){
var password = $("#MyPassword").val();
copyText(password);
return false;
},
btn4:function(layerIndex){
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
btn: ['确定', '取消']
}, function(index, layero){
layer.close(index);
var password = $("#MyPassword").val();
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
layer.close(layerIndex);
dbList();
},{icon: rdata.status ? 1 : 2});
});
});
return false;
}
});
}
@@ -674,7 +701,7 @@ function setDbPass(id, username, password){
<span title='随机密码' class='glyphicon glyphicon-repeat cursor' onclick='repeatPwd(16)'></span></div>\
</div>\
<input type='hidden' name='id' value='"+id+"'>\
</form>",
</form>",
yes:function(index){
// var data = $("#mod_pwd").serialize();
var data = {};
@@ -877,7 +904,7 @@ function openPhpmyadmin(name,username,password){
setTimeout(function(){
$("#toPHPMyAdmin").submit();
},3000);
},2000);
layer.msg('phpMyAdmin['+data.data+']需要手动登录😭',{icon:16,shade: [0.3, '#000'],time:4000});
} else{
@@ -890,7 +917,7 @@ function openPhpmyadmin(name,username,password){
setTimeout(function(){
$("#toPHPMyAdmin").submit();
},3000);
},2000);
}
}
@@ -1281,6 +1308,7 @@ function myBinRollingLogs(_name, func, _args, line){
}
});
}
function myBinLogsRender(page){
var _data = {};
if (typeof(page) =='undefined'){
@@ -2567,10 +2595,20 @@ function masterOrSlaveConf(version=''){
</div>\
</form>",
success:function(){
// copyText(v['Error']);
// $('.class-copy-db-err').click(function(){
// copyText(v['Error']);
// });
if (info['Last_IO_Error'] != ''){
copyText(info['Last_IO_Error']);
return;
}
if (info['Last_SQL_Error'] != ''){
copyText(info['Last_SQL_Error']);
return;
}
if (info['Slave_SQL_Running_State'] != ''){
copyText(info['Slave_SQL_Running_State']);
return;
}
},
yes:function(){
if (info['Last_IO_Error'] != ''){
@@ -2665,7 +2703,7 @@ function masterOrSlaveConf(version=''){
<p class="conf_p">\
<span class="f14 c6 mr20">Master[主]配置</span><span class="f14 c6 mr20"></span>\
<button class="btn '+(!rdata.status ? 'btn-danger' : 'btn-success')+' btn-xs btn-master">'+(!rdata.status ? '未开启' : '已开启') +'</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()" >重置</button>\
<button class="btn btn-success btn-xs" onclick="resetMaster()">重置</button>\
</p>\
<hr/>\
<!-- master list -->\
+1 -1
View File
@@ -159,7 +159,7 @@ Install_mysql()
apt install -y libssl-dev
apt install -y libgssglue-dev
apt install -y software-properties-common
add-apt-repository ppa:ubuntu-toolchain-r/test
add-apt-repository -y ppa:ubuntu-toolchain-r/test
LIBTIRPC_VER=`pkg-config libtirpc --modversion`
if [ ! -f ${mysqlDir}/libtirpc_1.3.3.orig.tar.bz2 ];then
+236
View File
@@ -0,0 +1,236 @@
# -*- coding: utf-8 -*-
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.7.html
#https://dev.mysql.com/downloads/file/?id=489855
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mysqlDir=${serverPath}/source/mysql
_os=`uname`
echo "use system: ${_os}"
if [ ${_os} == "Darwin" ]; then
OSNAME='macos'
elif grep -Eq "openSUSE" /etc/*-release; then
OSNAME='opensuse'
zypper refresh
elif grep -Eq "FreeBSD" /etc/*-release; then
OSNAME='freebsd'
pkg install -y wget unzip
elif grep -Eqi "Arch" /etc/issue || grep -Eq "Arch" /etc/*-release; then
OSNAME='arch'
echo y | pacman -Sy unzip
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then
OSNAME='centos'
yum install -y wget zip unzip
elif grep -Eqi "Fedora" /etc/issue || grep -Eq "Fedora" /etc/*-release; then
OSNAME='fedora'
yum install -y wget zip unzip
elif grep -Eqi "Rocky" /etc/issue || grep -Eq "Rocky" /etc/*-release; then
OSNAME='rocky'
yum install -y wget zip unzip
elif grep -Eqi "AlmaLinux" /etc/issue || grep -Eq "AlmaLinux" /etc/*-release; then
OSNAME='alma'
yum install -y wget zip unzip
elif grep -Eqi "Debian" /etc/issue || grep -Eq "Debian" /etc/*-release; then
OSNAME='debian'
apt update -y
apt install -y devscripts
apt install -y wget zip unzip
elif grep -Eqi "Ubuntu" /etc/issue || grep -Eq "Ubuntu" /etc/*-release; then
OSNAME='ubuntu'
apt install -y wget zip unzip
else
OSNAME='unknow'
fi
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
VERSION=8.2.0
Install_mysql()
{
mkdir -p ${mysqlDir}
echo '正在安装脚本文件...' > $install_tmp
if id mysql &> /dev/null ;then
echo "mysql UID is `id -u www`"
echo "mysql Shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
else
groupadd mysql
useradd -g mysql mysql
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
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
cd ${rootPath}/plugins/mysql/lib && /bin/bash rpcgen.sh
INSTALL_CMD=cmake
# check cmake version
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
if [ "$CMAKE_VERSION" -eq "2" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
INSTALL_CMD=cmake3
fi
if [ ! -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
#wget --no-check-certificate -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
wget --no-check-certificate -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-8.2/mysql-boost-${VERSION}.tar.gz
fi
#检测文件是否损坏.
md5_mysql_ok=704ad9fb4779e76ce5e327285813c97c
if [ -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
md5_mysql=`md5sum ${mysqlDir}/mysql-boost-${VERSION}.tar.gz | awk '{print $1}'`
if [ "${md5_mysql_ok}" == "${md5_mysql}" ]; then
echo "mysql8.0 file check ok"
else
# 重新下载
rm -rf ${mysqlDir}/mysql-${VERSION}
wget --no-check-certificate -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
fi
fi
if [ ! -d ${mysqlDir}/mysql-${VERSION} ];then
cd ${mysqlDir} && tar -zxvf ${mysqlDir}/mysql-boost-${VERSION}.tar.gz
fi
OPTIONS=''
##check openssl version
OPENSSL_VERSION=`openssl version|awk '{print $2}'|awk -F '.' '{print $1}'`
if [ "${OPENSSL_VERSION}" -ge "3" ];then
#openssl version to high
cd ${rootPath}/plugins/php/lib && /bin/bash openssl.sh
export PKG_CONFIG_PATH=$serverPath/lib/openssl/lib/pkgconfig
OPTIONS="-DWITH_SSL=${serverPath}/lib/openssl"
fi
WHERE_DIR_GCC=/usr/bin/gcc
WHERE_DIR_GPP=/usr/bin/g++
if [ "$OSNAME" == "centos" ] && [ "$VERSION_ID" == "7" ];then
yum install -y libudev-devel
yum install -y centos-release-scl
yum install -y devtoolset-11-gcc devtoolset-11-gcc-c++ devtoolset-11-binutils
gcc --version
WHERE_DIR_GCC=/opt/rh/devtoolset-11/root/usr/bin/gcc
WHERE_DIR_GPP=/opt/rh/devtoolset-11/root/usr/bin/g++
echo $WHERE_DIR_GCC
echo $WHERE_DIR_GPP
fi
if [ "$OSNAME" == "ubuntu" ];then
apt install -y libudev-dev
apt install -y libtirpc-dev
apt install -y libssl-dev
apt install -y libgssglue-dev
apt install -y software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
LIBTIRPC_VER=`pkg-config libtirpc --modversion`
if [ ! -f ${mysqlDir}/libtirpc_1.3.3.orig.tar.bz2 ];then
wget --no-check-certificate -O ${mysqlDir}/libtirpc_1.3.3.orig.tar.bz2 https://downloads.sourceforge.net/libtirpc/libtirpc-1.3.3.tar.bz2
cd ${mysqlDir} && tar -jxvf libtirpc_1.3.3.orig.tar.bz2
cd libtirpc-1.3.3 && ./configure
fi
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
apt install -y gcc-11 g++-11
WHERE_DIR_GCC=/usr/bin/gcc-11
WHERE_DIR_GPP=/usr/bin/g++-11
fi
if [ "$OSNAME" == "opensuse" ];then
zypper install -y gcc11
zypper install -y gcc11-c++
WHERE_DIR_GCC=/usr/bin/gcc-11
WHERE_DIR_GPP=/usr/bin/g++-11
fi
if [ ! -d $serverPath/mysql ];then
# -DCMAKE_CXX_STANDARD=17 \
cd ${mysqlDir}/mysql-${VERSION} && ${INSTALL_CMD} \
-DCMAKE_INSTALL_PREFIX=$serverPath/mysql \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DMYSQL_UNIX_ADDR=/var/tmp/mysql.sock \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DDOWNLOAD_BOOST=1 \
-DFORCE_INSOURCE_BUILD=1 \
$OPTIONS \
-DCMAKE_C_COMPILER=$WHERE_DIR_GCC \
-DCMAKE_CXX_COMPILER=$WHERE_DIR_GPP \
-DDOWNLOAD_BOOST=0 \
-DWITH_BOOST=${mysqlDir}/mysql-${VERSION}/boost/
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mysql ];then
rm -rf ${mysqlDir}/mysql-${VERSION}
echo '8.2' > $serverPath/mysql/version.pl
echo "${VERSION}安装完成"
else
# rm -rf ${mysqlDir}/mysql-${VERSION}
echo "${VERSION}安装失败"
echo 'install fail'>&2
exit 1
fi
fi
}
Uninstall_mysql()
{
rm -rf $serverPath/mysql
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == "install" ];then
Install_mysql
else
Uninstall_mysql
fi
+6
View File
@@ -579,6 +579,12 @@ def reload():
mw.opWeb('start')
return 'ok'
def reload_hook():
s = status()
if s == 'start':
return reload()
return 'ok'
def getJsonPath(name):
path = getServerDir() + "/waf/" + name + ".json"
+3 -3
View File
@@ -5,9 +5,9 @@
"site_cb": {
"title":"网站统计",
"name":"op_waf",
"add":{"func":"reload"},
"update":{"func":"reload"},
"delete":{"func":"reload"}
"add":{"func":"reload_hook"},
"update":{"func":"reload_hook"},
"delete":{"func":"reload_hook"}
}
}
],
+2 -2
View File
@@ -1,5 +1,5 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
# cd /www/server/mdserver-web/plugins/op_waf && bash install.sh install 0.4.1
@@ -87,7 +87,7 @@ Install_App(){
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
HTTP_PREFIX="https://"
if [ ! -z "$cn" ];then
HTTP_PREFIX="https://ghproxy.com/"
HTTP_PREFIX="https://mirror.ghproxy.com/"
fi
# download GeoLite Data
+2 -1
View File
@@ -1614,8 +1614,9 @@ function wafSite(){
<label class="btswitch-btn" for="closeget_'+ i + '" onclick="setSiteObjState(\'' + k + '\',\'open\')"></label>\
</div>\
</td>\
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> </td>\
</tr>';
//| <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a>
});
var con = '<div class="lib-box">\
+1 -1
View File
@@ -3,7 +3,7 @@ worker_processes auto;
error_log {$SERVER_PATH}/openresty/nginx/logs/error.log crit;
pid {$SERVER_PATH}/openresty/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
worker_rlimit_nofile 65535;
events
{
+3 -2
View File
@@ -1,8 +1,9 @@
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="orPluginService('openresty');">服务</p>
<p onclick="pluginInitD('openresty');">自启动</p>
<p class="bgw" onclick="orPluginService('openresty',$('.plugin_version').attr('version'));">服务</p>
<p onclick="pluginInitD('openresty', $('.plugin_version').attr('version'));">自启动</p>
<p onclick="pluginConfig('openresty');">配置修改</p>
<p onclick="getOpStatus();">负载状态</p>
<p onclick="setOpCfg();">性能调整</p>
+2 -2
View File
@@ -320,7 +320,7 @@ def restyOp_restart():
return 'ERROR: 配置出错<br><a style="color:red;">' + check_data[1].replace("\n", '<br>') + '</a>'
if not mw.isAppleSystem():
threading.Timer(2, op_submit_systemctl_restart, args=()).start()
threading.Timer(2, op_submit_systemctl_restart).start()
return 'ok'
threading.Timer(2, op_submit_init_restart, args=(file,)).start()
@@ -339,7 +339,7 @@ def stop():
return r
def restart():
def restart(version=()):
return restyOp_restart()
+1 -1
View File
@@ -79,7 +79,7 @@ Install_openresty()
# Last Download Method
if [ ! -f ${openrestyDir}/openresty-${VERSION}.tar.gz ];then
wget --no-check-certificate -O ${openrestyDir}/openresty-${VERSION}.tar.gz http://dl.midoks.me/soft/openresty/openresty-${VERSION}.tar.gz -T 3
wget --no-check-certificate -O ${openrestyDir}/openresty-${VERSION}.tar.gz http://dl.midoks.icu/soft/openresty/openresty-${VERSION}.tar.gz -T 3
fi
cd ${openrestyDir} && tar -zxvf openresty-${VERSION}.tar.gz
+2 -4
View File
@@ -1,7 +1,7 @@
<style type="text/css">
.bt-w-main{
height: 600px;
height: 552px;
}
.session_clear_list {
@@ -44,8 +44,7 @@
<p onclick="pluginInitD('php-apt', $('.plugin_version').attr('version'));">自启动</p>
<p onclick="phpLibConfig($('.plugin_version').attr('version'));">安装扩展</p>
<p onclick="phpSetConfig($('.plugin_version').attr('version'));">配置修改</p>
<p onclick="phpUploadLimitReq($('.plugin_version').attr('version'));">上传限制</p>
<p onclick="phpTimeLimitReq($('.plugin_version').attr('version'));">超时限制</p>
<p onclick="phpCommonFunc($('.plugin_version').attr('version'));">常用功能</p>
<p onclick="pluginConfig('php-apt', $('.plugin_version').attr('version'));">配置文件</p>
<p onclick="pluginConfig('php-apt', $('.plugin_version').attr('version'),'get_fpm_conf_file');">FPM配置</p>
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
@@ -54,7 +53,6 @@
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php-apt',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php-apt',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
+171
View File
@@ -0,0 +1,171 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import shutil
# reload(sys)
# sys.setdefaultencoding('utf8')
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 'php-apt'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return '/etc/php'
def getInitDFile(version):
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName() + version
def getConf(version):
path = getServerDir() + '/' + version + '/fpm/php.ini'
return path
def getFpmConfFile(version):
return getServerDir() + '/' + version + '/fpm/pool.d/mw.conf'
def status_progress(version):
# ps -ef|grep 'php/81' |grep -v grep | grep -v python | awk '{print $2}
cmd = "ps aux|grep 'php/" + version + \
"' |grep -v grep | grep -v python | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return 'stop'
return 'start'
def getPhpSocket(version):
path = getFpmConfFile(version)
content = mw.readFile(path)
rep = 'listen\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def status(version):
'''
sock文件判断是否启动
'''
sock = getPhpSocket(version)
if sock.find(':'):
return status_progress(version)
if not os.path.exists(sock):
return 'stop'
return 'start'
def getFpmAddress(version):
fpm_address = '/run/php/php{}-fpm.sock'.format(version)
php_fpm_file = getFpmConfFile(version)
try:
content = readFile(php_fpm_file)
tmp = re.findall(r"listen\s*=\s*(.+)", content)
if not tmp:
return fpm_address
if tmp[0].find('sock') != -1:
return fpm_address
if tmp[0].find(':') != -1:
listen_tmp = tmp[0].split(':')
if bind:
fpm_address = (listen_tmp[0], int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1', int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1', int(tmp[0]))
return fpm_address
except:
return fpm_address
def getPhpinfo(version):
stat = status(version)
if stat == 'stop':
return 'PHP[' + version + ']未启动,不可访问!!!'
sock_file = getFpmAddress(version)
print(sock_file)
root_dir = mw.getRootDir() + '/phpinfo'
mw.execShell("rm -rf " + root_dir)
mw.execShell("mkdir -p " + root_dir)
mw.writeFile(root_dir + '/phpinfo.php', '<?php phpinfo(); ?>')
sock_data = mw.requestFcgiPHP(sock_file, '/phpinfo.php', root_dir)
os.system("rm -rf " + root_dir)
phpinfo = str(sock_data, encoding='utf-8')
return phpinfo
def libConfCommon(version):
fname = getConf(version)
if not os.path.exists(fname):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(fname)
libpath = getPluginDir() + '/versions/phplib.conf'
phplib = json.loads(mw.readFile(libpath))
libs = []
tasks = mw.M('tasks').where(
"status!=?", ('1',)).field('status,name').select()
for lib in phplib:
lib['task'] = '1'
for task in tasks:
tmp = mw.getStrBetween('[', ']', task['name'])
if not tmp:
continue
tmp1 = tmp.split('-')
if tmp1[0].lower() == lib['name'].lower():
lib['task'] = task['status']
lib['phpversions'] = []
lib['phpversions'].append(tmp1[1])
if phpini.find(lib['check']) == -1:
lib['status'] = False
else:
lib['status'] = True
libs.append(lib)
return libs
def get_php_info(args):
version = args['version']
apt_ver = version[0:1]+'.'+version[1:2]
return getPhpinfo(apt_ver)
def get_lib_conf(data):
libs = libConfCommon(data['version'])
return mw.returnData(True, 'OK!', libs)
+1 -1
View File
@@ -5,7 +5,7 @@
"name": "php-apt",
"title": "PHP[APT]",
"coexist": true,
"versions": ["56","70","71","72","73","74","80","81","82"],
"versions": ["56","70","71","72","73","74","80","81","82","83"],
"install_pre_inspection":true,
"tip": "soft",
"checks": "server/php-apt/VERSION",
+35 -40
View File
@@ -1,14 +1,3 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function phpPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@@ -18,7 +7,7 @@ function phpPost(method, version, args,callback){
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -43,10 +32,11 @@ function phpPostCallbak(method, version, args,callback){
var req_data = {};
req_data['name'] = 'php-apt';
req_data['func'] = method;
req_data['script']='index_php_apt';
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -128,35 +118,29 @@ function submitConf(version) {
});
}
//php上传限制
function phpUploadLimitReq(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpUploadLimit(version,rdata['max']);
});
}
function phpUploadLimit(version,max){
var LimitCon = '<p class="conf_p"><input class="phpUploadLimit bt-input-text mr5" type="number" value="'+
max+'" name="max">MB<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+
version+'\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
}
//php超时限制
function phpTimeLimitReq(version){
function phpCommonFunc(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpTimeLimit(version,rdata['maxTime']);
});
}
var con = '<p class="conf_p">\
<span>超时限制</span>\
<input class="phpTimeLimit bt-input-text mr5" type="number" value="' + rdata['maxTime'] + '">, 秒\
<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button>\
</p>';
function phpTimeLimit(version, max) {
var LimitCon = '<p class="conf_p"><input class="phpTimeLimit bt-input-text mr5" type="number" value="' + max + '">秒<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
con += '<p class="conf_p">\
<span>上传限制</span>\
<input class="phpUploadLimit bt-input-text mr5" type="number" value="' + rdata['max']+'" name="max">,MB\
<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+ version+'\')" style="margin-left:20px">保存</button>\
</p>';
// <button class="btn btn-default btn-sm" onclick="phpPreload(\'' + version + '\')">预加载脚本</button>\
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button> \
</p>';
$(".soft-man-con").html(con);
});
}
//设置超时限制
@@ -164,7 +148,10 @@ function setPHPMaxTime(version) {
var max = $(".phpTimeLimit").val();
phpPost('set_max_time',version,{'time':max},function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
showMsg(rdata.msg,function(){
phpCommonFunc(version);
},{ icon: rdata.status ? 1 : 2 });
});
}
//设置PHP上传限制
@@ -182,6 +169,13 @@ function setPHPMaxSize(version) {
});
}
function phpPreload(version){
phpPost('app_start',version,{},function(data){
onlineEditFile(0, data['data']);
});
}
function getFpmConfig(version){
phpPost('get_fpm_conf', version, {}, function(data){
@@ -320,6 +314,7 @@ function getFpmStatus(version){
return;
}
var rdata = tmp_data.data;
var php_fpm_status = '动态';
if (rdata['process manager'] == 'dynamic'){
php_fpm_status = '动态';
@@ -329,7 +324,7 @@ function getFpmStatus(version){
php_fpm_status = '按需';
}
var rdata = tmp_data.data;
var con = "<div style='height:420px;overflow:hidden;'><table class='table table-hover table-bordered GetPHPStatus' style='margin:0;padding:0'>\
<tr><th>应用池(pool)</th><td>" + rdata.pool + "</td></tr>\
<tr><th>进程管理方式(process manager)</th><td>" + php_fpm_status + "</td></tr>\
+49
View File
@@ -0,0 +1,49 @@
#!/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")
sourcePath=${serverPath}/source
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
#获取信息和版本
# bash /www/server/mdsever-web/scripts/getos.sh
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
version=8.3
PHP_VER=83
Install_php()
{
#------------------------ install start ------------------------------------#
apt -y install php${version} php${version}-fpm php${version}-dev
if [ "$?" == "0" ];then
mkdir -p $serverPath/php-apt/${PHP_VER}
fi
#------------------------ install end ------------------------------------#
}
Uninstall_php()
{
#------------------------ uninstall start ------------------------------------#
apt -y remove php${version} php${version}-*
rm -rf $serverPath/php-apt/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
#------------------------ uninstall start ------------------------------------#
}
action=${1}
if [ "${1}" == 'install' ];then
Install_php
else
Uninstall_php
fi
+51 -22
View File
@@ -10,7 +10,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "数据库访问抽象模块!",
@@ -28,7 +29,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@@ -46,7 +48,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@@ -64,7 +67,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用sqlite3数据库的模块!",
@@ -90,7 +94,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用ODBC数据库的模块!",
@@ -142,7 +147,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "用于加速PHP脚本!",
@@ -175,7 +181,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "高精度计算!",
@@ -239,7 +246,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用CURL库!",
@@ -252,7 +260,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用GD库!",
@@ -270,7 +279,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "提供国际化支持",
@@ -300,7 +310,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "强大的内容缓存器,支持集群",
@@ -317,7 +328,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "更强大的内容缓存器,支持集群",
@@ -334,7 +347,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "脚本缓存器",
@@ -352,7 +367,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "比GD更强大的图形库",
@@ -369,7 +385,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "调试器",
"msg": "不多说,不了解的不要安装",
@@ -386,7 +404,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "性能分析",
"msg": "不多说,不了解的不要安装!",
@@ -403,7 +423,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "异步、并行、高性能网络通信引擎",
@@ -463,7 +485,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "框架",
"msg": "Yar是一个RPC框架",
@@ -541,7 +565,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "日志",
"msg": "SeasLog高性能日志记录",
@@ -559,7 +585,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "用于需要多字节字符串处理的模块",
@@ -577,7 +604,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
@@ -594,7 +622,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
+2 -4
View File
@@ -1,6 +1,6 @@
<style type="text/css">
.bt-w-main{
height: 600px;
height: 552px;
}
.session_clear_list {
@@ -43,8 +43,7 @@
<p onclick="pluginInitD('php-yum', $('.plugin_version').attr('version'));">自启动</p>
<p onclick="phpLibConfig($('.plugin_version').attr('version'));">安装扩展</p>
<p onclick="phpSetConfig($('.plugin_version').attr('version'));">配置修改</p>
<p onclick="phpUploadLimitReq($('.plugin_version').attr('version'));">上传限制</p>
<p onclick="phpTimeLimitReq($('.plugin_version').attr('version'));">超时限制</p>
<p onclick="phpCommonFunc($('.plugin_version').attr('version'));">常用功能</p>
<p onclick="pluginConfig('php-yum', $('.plugin_version').attr('version'));">配置文件</p>
<p onclick="pluginConfig('php-yum', $('.plugin_version').attr('version'),'get_fpm_conf_file');">FPM配置</p>
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
@@ -53,7 +52,6 @@
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php-yum',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php-yum',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
+1 -1
View File
@@ -5,7 +5,7 @@
"name": "php-yum",
"title": "PHP[YUM]",
"coexist": true,
"versions": ["74","80","81","82"],
"versions": ["74","80","81","82","83"],
"install_pre_inspection":true,
"tip": "soft",
"checks": "server/php-yum/VERSION",
+37 -43
View File
@@ -1,14 +1,3 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function phpPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@@ -18,7 +7,7 @@ function phpPost(method, version, args,callback){
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -46,7 +35,7 @@ function phpPostCallbak(method, version, args,callback){
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -130,33 +119,29 @@ function submitConf(version) {
//php上传限制
function phpUploadLimitReq(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpUploadLimit(version,rdata['max']);
});
}
function phpUploadLimit(version,max){
var LimitCon = '<p class="conf_p"><input class="phpUploadLimit bt-input-text mr5" type="number" value="'+
max+'" name="max">MB<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+
version+'\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
}
//php超时限制
function phpTimeLimitReq(version){
function phpCommonFunc(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpTimeLimit(version,rdata['maxTime']);
});
}
var con = '<p class="conf_p">\
<span>超时限制</span>\
<input class="phpTimeLimit bt-input-text mr5" type="number" value="' + rdata['maxTime'] + '">, 秒\
<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button>\
</p>';
function phpTimeLimit(version, max) {
var LimitCon = '<p class="conf_p"><input class="phpTimeLimit bt-input-text mr5" type="number" value="' + max + '">秒<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
con += '<p class="conf_p">\
<span>上传限制</span>\
<input class="phpUploadLimit bt-input-text mr5" type="number" value="' + rdata['max']+'" name="max">,MB\
<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+ version+'\')" style="margin-left:20px">保存</button>\
</p>';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button> \
<button class="btn btn-default btn-sm" onclick="phpPreload(\'' + version + '\')">预加载脚本</button>\
</p>';
$(".soft-man-con").html(con);
});
}
//设置超时限制
@@ -164,7 +149,10 @@ function setPHPMaxTime(version) {
var max = $(".phpTimeLimit").val();
phpPost('set_max_time',version,{'time':max},function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
showMsg(rdata.msg,function(){
phpCommonFunc(version);
},{ icon: rdata.status ? 1 : 2 });
});
}
//设置PHP上传限制
@@ -182,6 +170,12 @@ function setPHPMaxSize(version) {
});
}
function phpPreload(version){
phpPost('app_start',version,{},function(data){
onlineEditFile(0, data['data']);
});
}
function getFpmConfig(version){
phpPost('get_fpm_conf', version, {}, function(data){
@@ -326,6 +320,7 @@ function getFpmStatus(version){
return;
}
var rdata = tmp_data.data;
var php_fpm_status = '动态';
if (rdata['process manager'] == 'dynamic'){
php_fpm_status = '动态';
@@ -334,8 +329,7 @@ function getFpmStatus(version){
} else if(rdata['process manager'] == 'ondemand'){
php_fpm_status = '按需';
}
var rdata = tmp_data.data;
var con = "<div style='height:420px;overflow:hidden;'><table class='table table-hover table-bordered GetPHPStatus' style='margin:0;padding:0'>\
<tr><th>应用池(pool)</th><td>" + rdata.pool + "</td></tr>\
<tr><th>进程管理方式(process manager)</th><td>" + php_fpm_status + "</td></tr>\
@@ -564,10 +558,10 @@ function setDisableFunc(version, act, fs) {
//phpinfo
function getPhpinfo(version) {
var con = '<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button>';
$(".soft-man-con").html(con);
}
// function getPhpinfo(version) {
// var con = '<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button>';
// $(".soft-man-con").html(con);
// }
//获取PHPInfo
function getPHPInfo_old(version) {
+41
View File
@@ -0,0 +1,41 @@
#!/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")
sourcePath=${serverPath}/source
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
version=8.3.x
PHP_VER=83
Install_php()
{
#------------------------ install start ------------------------------------#
yum install -y php83 php83-php-fpm
if [ "$?" == "0" ];then
mkdir -p $serverPath/php-yum/${PHP_VER}
fi
#------------------------ install end ------------------------------------#
}
Uninstall_php()
{
yum remove -y php83 php83-php-fpm php83-*
rm -rf $serverPath/php-yum/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
}
action=${1}
if [ "${1}" == 'install' ];then
Install_php
else
Uninstall_php
fi
+64 -25
View File
@@ -5,7 +5,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "数据库访问抽象模块!",
@@ -18,7 +19,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@@ -31,7 +33,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
@@ -44,7 +47,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用OCI8数据库的模块!",
@@ -57,7 +61,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "数据库",
"msg": "用于使用ODBC数据库的模块!",
@@ -128,7 +133,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "用于加速PHP脚本!",
@@ -163,7 +169,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "用于FILE!",
@@ -183,7 +191,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "用于XML!",
@@ -203,7 +213,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "用于图像文件格式!",
@@ -216,7 +228,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用GD库!",
@@ -238,7 +251,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "提供国际化支持",
@@ -271,7 +285,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "强大的内容缓存器,支持集群",
@@ -292,7 +307,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "更强大的内容缓存器,支持集群",
@@ -323,7 +340,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "比GD更强大的图形库",
@@ -343,7 +361,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "调试器",
"msg": "不多说,不了解的不要安装",
@@ -364,7 +384,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "性能分析",
"msg": "不多说,不了解的不要安装!",
@@ -384,7 +406,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "异步、并行、高性能网络通信引擎",
@@ -415,7 +439,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "框架",
"msg": "Yaf是一个C语言编写的PHP框架",
@@ -435,7 +461,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "框架",
"msg": "Yar是一个RPC框架",
@@ -466,7 +494,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "通用扩展",
"msg": "Mongodb数据库连接驱动",
@@ -482,7 +512,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "缓存器",
"msg": "高性能无锁共享内存Cache",
@@ -502,7 +534,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "大数据",
"msg": "SOLR全文搜索服务",
@@ -522,7 +556,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "日志",
"msg": "SeasLog高性能日志记录",
@@ -543,7 +579,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "用于需要多字节字符串处理的模块",
@@ -560,7 +597,9 @@
"74",
"80",
"81",
"82"
"82",
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
+4
View File
@@ -1,5 +1,9 @@
<?php
if (isset($_GET['mw_opcache_reset']) && $_GET['mw_opcache_reset'] == 'ok'){
opcache_reset();
}
define('XHProf_Name', 'mdd');
/**
+19
View File
@@ -0,0 +1,19 @@
[backup]
user = {$PHP_USER}
group = {$PHP_GROUP}
listen = /tmp/php-cgi-{$PHP_VERSION}.backup.sock
listen.owner = {$PHP_USER}
listen.group = {$PHP_GROUP}
listen.backlog = 4096
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.status_path = /phpfpm_status_{$PHP_VERSION}_backup
pm.max_requests = 1000
request_terminate_timeout = 30
request_slowlog_timeout = 10
slowlog = {$SERVER_PATH}/php/{$PHP_VERSION}/var/log/www-slow.log
@@ -0,0 +1,4 @@
upstream MW-UPSTREAM-PHP{$PHP_VERSION} {
server unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
server unix:/tmp/php-cgi-{$PHP_VERSION}.backup.sock;
}
+9
View File
@@ -0,0 +1,9 @@
set $PHP_ENV 1;
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
fastcgi_index index.php;
include fastcgi.conf;
include {$SERVER_PATH}/web_conf/php/pathinfo.conf;
}
+2 -1
View File
@@ -2,7 +2,8 @@ set $PHP_ENV 1;
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
#fastcgi_pass unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
fastcgi_pass MW-UPSTREAM-PHP{$PHP_VERSION};
fastcgi_index index.php;
include fastcgi.conf;
include {$SERVER_PATH}/web_conf/php/pathinfo.conf;
+2 -2
View File
@@ -8,10 +8,10 @@ listen.group = {$PHP_GROUP}
listen.backlog = 4096
pm = dynamic
pm.max_children = 50
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_spare_servers = 20
pm.status_path = /phpfpm_status_{$PHP_VERSION}
pm.max_requests = 1000
request_terminate_timeout = 30
+3 -6
View File
@@ -1,7 +1,7 @@
<style type="text/css">
.bt-w-main{
height: 642px;
height: 552px;
}
.session_clear_list {
@@ -43,18 +43,15 @@
<p onclick="pluginInitD('php', $('.plugin_version').attr('version'));">自启动</p>
<p onclick="phpLibConfig($('.plugin_version').attr('version'));">安装扩展</p>
<p onclick="phpSetConfig($('.plugin_version').attr('version'));">配置修改</p>
<p onclick="phpUploadLimitReq($('.plugin_version').attr('version'));">上传限制</p>
<p onclick="phpTimeLimitReq($('.plugin_version').attr('version'));">超时限制</p>
<p onclick="phpCommonFunc($('.plugin_version').attr('version'));">常用功能</p>
<p onclick="pluginConfig('php', $('.plugin_version').attr('version'));">配置文件</p>
<p onclick="pluginConfig('php', $('.plugin_version').attr('version'),'get_fpm_conf_file');">FPM配置</p>
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
<p onclick="phpFpmConfigFile($('.plugin_version').attr('version'),'get_fpm_conf_file');">FPM配置</p>
<p onclick="getFpmConfig($('.plugin_version').attr('version'));">性能调整</p>
<p onclick="getFpmStatus($('.plugin_version').attr('version'));">负载状况</p>
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
<p onclick="pluginConfig('php',$('.plugin_version').attr('version'),'app_start');">预加载脚本</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
+77 -31
View File
@@ -59,7 +59,6 @@ def getArgs():
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
@@ -79,8 +78,14 @@ def getConf(version):
return path
def getFpmConfFile(version):
return getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf'
def getFpmConfFile(version, pool='www'):
args = getArgs()
if 'pool' in args:
pool = args['pool']
return getServerDir() + '/' + version + '/etc/php-fpm.d/'+pool+'.conf'
def getFpmFile(version):
return getServerDir() + '/' + version + '/etc/php-fpm.conf'
def status_progress(version):
@@ -157,17 +162,21 @@ def makeOpenrestyConf():
sdir = mw.getServerDir()
dst_dir = sdir + '/web_conf/php'
dst_dir_conf = sdir + '/web_conf/php/conf'
if not os.path.exists(dst_dir):
mw.execShell('mkdir -p ' + dst_dir)
dst_dir_conf = sdir + '/web_conf/php/conf'
if not os.path.exists(dst_dir_conf):
mw.execShell('mkdir -p ' + dst_dir_conf)
d_pathinfo = sdir + '/web_conf/php/pathinfo.conf'
if not os.path.exists(d_pathinfo):
s_pathinfo = getPluginDir() + '/conf/pathinfo.conf'
shutil.copyfile(s_pathinfo, d_pathinfo)
dst_dir_upstream = sdir + '/web_conf/php/upstream'
if not os.path.exists(dst_dir_upstream):
mw.execShell('mkdir -p ' + dst_dir_upstream)
dst_pathinfo = sdir + '/web_conf/php/pathinfo.conf'
if not os.path.exists(dst_pathinfo):
src_pathinfo = getPluginDir() + '/conf/pathinfo.conf'
shutil.copyfile(src_pathinfo, dst_pathinfo)
info = getPluginDir() + '/info.json'
content = mw.readFile(info)
@@ -179,19 +188,31 @@ def makeOpenrestyConf():
dfile = sdir + '/web_conf/php/conf/enable-php-' + x + '.conf'
if not os.path.exists(dfile):
if x == '00':
mw.writeFile(dfile, 'set $PHP_ENV 0;')
mw.writeFile(dfile, '')
else:
w_content = contentReplace(tpl_content, x)
mw.writeFile(dfile, w_content)
content = contentReplace(tpl_content, x)
mw.writeFile(dfile, content)
upstream_tpl = getPluginDir() + '/conf/enable-php-upstream.conf'
upstream_tpl_content = mw.readFile(upstream_tpl)
for x in phpversions:
dfile = sdir + '/web_conf/php/upstream/enable-php-' + x + '.conf'
if not os.path.exists(dfile):
if x == '00':
mw.writeFile(dfile, '')
else:
content = contentReplace(upstream_tpl_content, x)
mw.writeFile(dfile, content)
vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost'
write_php_upstream_conf = mw.getServerDir()+'/web_conf/php/upstream/*.conf;'
if not os.path.exists(vhost_dir):
mw.execShell('mkdir -p ' + vhost_dir)
vhost_php_upstream = vhost_dir+'/0.php_upstream.conf'
if not os.path.exists(vhost_php_upstream):
mw.writeFile(vhost_php_upstream,'include '+write_php_upstream_conf)
# php-fpm status
# for version in phpversions:
# dfile = sdir + '/web_conf/php/status/phpfpm_status_' + version + '.conf'
# tpl = getPluginDir() + '/conf/phpfpm_status.conf'
# if not os.path.exists(dfile):
# content = mw.readFile(tpl)
# content = contentReplace(content, version)
# mw.writeFile(dfile, content)
def phpPrependFile(version):
@@ -217,15 +238,16 @@ def phpFpmReplace(version):
mw.writeFile(desc_php_fpm, content)
def phpFpmWwwReplace(version):
def phpFpmPoolReplace(version, pool = 'www'):
service_php_fpm_dir = getServerDir() + '/' + version + '/etc/php-fpm.d/'
if not os.path.exists(service_php_fpm_dir):
os.mkdir(service_php_fpm_dir)
service_php_fpmwww = service_php_fpm_dir + '/www.conf'
service_php_fpmwww = service_php_fpm_dir + '/'+pool+'.conf'
if not os.path.exists(service_php_fpmwww):
tpl_php_fpmwww = getPluginDir() + '/conf/www.conf'
tpl_php_fpmwww = getPluginDir() + '/conf/'+pool+'.conf'
content = mw.readFile(tpl_php_fpmwww)
content = contentReplace(content, version)
mw.writeFile(service_php_fpmwww, content)
@@ -266,7 +288,8 @@ def initReplace(version):
mw.execShell('chmod +x ' + file_bin)
phpPrependFile(version)
phpFpmWwwReplace(version)
phpFpmPoolReplace(version, 'www')
phpFpmPoolReplace(version, 'backup')
phpFpmReplace(version)
session_path = getServerDir() + '/tmp/session'
@@ -539,9 +562,13 @@ def setMaxSize(version):
return mw.returnJson(True, '设置成功!')
def getFpmConfig(version):
def getFpmConfig(version, pool = 'www'):
args = getArgs()
pool = 'www'
if 'pool' in args:
pool = args['pool']
filefpm = getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf'
filefpm = getServerDir() + '/' + version + '/etc/php-fpm.d/'+pool+'.conf'
conf = mw.readFile(filefpm)
data = {}
rep = "\s*pm.max_children\s*=\s*([0-9]+)\s*"
@@ -577,8 +604,10 @@ def setFpmConfig(version):
min_spare_servers = args['min_spare_servers']
max_spare_servers = args['max_spare_servers']
pm = args['pm']
pool = args['pool']
file = getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf'
file = getServerDir() + '/' + version + '/etc/php-fpm.d/'+pool+'.conf'
conf = mw.readFile(file)
rep = "\s*pm.max_children\s*=\s*([0-9]+)\s*"
@@ -621,8 +650,10 @@ def setFpmConfig(version):
# return True
def getFpmAddress(version):
def getFpmAddress(version, pool='www'):
fpm_address = '/tmp/php-cgi-{}.sock'.format(version)
if pool != 'www':
fpm_address = '/tmp/php-cgi-{}.{}.sock'.format(version,pool)
php_fpm_file = getFpmConfFile(version)
try:
content = readFile(php_fpm_file)
@@ -653,14 +684,21 @@ def getFpmStatus(version):
if stat == 'stop':
return mw.returnJson(False, 'PHP[' + version + ']未启动!!!')
sock_file = getFpmAddress(version)
args = getArgs()
pool = 'www'
if 'pool' in args:
pool = args['pool']
sock_file = getFpmAddress(version, pool)
uri = '/phpfpm_status_' + version + '?json'
if pool != 'www':
uri = '/phpfpm_status_' + version + '_'+pool+'?json'
try:
sock_data = mw.requestFcgiPHP(
sock_file, '/phpfpm_status_' + version + '?json')
sock_data = mw.requestFcgiPHP(sock_file, uri)
except Exception as e:
return mw.returnJson(False, str(e))
# print(data)
result = str(sock_data, encoding='utf-8')
data = json.loads(result)
fTime = time.localtime(int(data['start time']))
@@ -976,6 +1014,10 @@ def getConfAppStart():
pstart = mw.getServerDir() + '/php/app_start.php'
return pstart
def opcacheBlacklistFile():
op_bl = mw.getServerDir() + '/php/opcache-blacklist.txt'
return op_bl
def installPreInspection(version):
# 仅对PHP52检查
@@ -1047,10 +1089,14 @@ if __name__ == "__main__":
print(getConf(version))
elif func == 'app_start':
print(getConfAppStart())
elif func == 'opcache_blacklist_file':
print(opcacheBlacklistFile())
elif func == 'get_php_conf':
print(getPhpConf(version))
elif func == 'get_fpm_conf_file':
print(getFpmConfFile(version))
elif func == 'get_fpm_file':
print(getFpmFile(version))
elif func == 'submit_php_conf':
print(submitPhpConf(version))
elif func == 'get_limit_conf':
+174 -39
View File
@@ -123,34 +123,31 @@ function submitConf(version) {
}
//php上传限制
function phpUploadLimitReq(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpUploadLimit(version,rdata['max']);
});
}
function phpUploadLimit(version,max){
var LimitCon = '<p class="conf_p"><input class="phpUploadLimit bt-input-text mr5" type="number" value="'+
max+'" name="max">MB<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+
version+'\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
}
//php超时限制
function phpTimeLimitReq(version){
function phpCommonFunc(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpTimeLimit(version,rdata['maxTime']);
});
}
var con = '<p class="conf_p">\
<span>超时限制</span>\
<input class="phpTimeLimit bt-input-text mr5" type="number" value="' + rdata['maxTime'] + '">, 秒\
<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button>\
</p>';
function phpTimeLimit(version, max) {
var LimitCon = '<p class="conf_p"><input class="phpTimeLimit bt-input-text mr5" type="number" value="' + max + '">秒<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
con += '<p class="conf_p">\
<span>上传限制</span>\
<input class="phpUploadLimit bt-input-text mr5" type="number" value="' + rdata['max']+'" name="max">,MB\
<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+ version+'\')" style="margin-left:20px">保存</button>\
</p>';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button> \
<button class="btn btn-default btn-sm" onclick="phpPreload(\'' + version + '\')">预加载脚本</button>\
<button class="btn btn-default btn-sm" onclick="phpOpcacheBlacklist(\'' + version + '\')">OPCACHE黑名单</button>\
<button class="btn btn-default btn-sm" onclick="phpFpmRoot(\'' + version + '\')">PHP-FPM(global)</button>\
</p>';
$(".soft-man-con").html(con);
});
}
//设置超时限制
@@ -158,7 +155,10 @@ function setPHPMaxTime(version) {
var max = $(".phpTimeLimit").val();
phpPost('set_max_time',version,{'time':max},function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
showMsg(rdata.msg,function(){
phpCommonFunc(version);
},{ icon: rdata.status ? 1 : 2 });
});
}
//设置PHP上传限制
@@ -176,9 +176,108 @@ function setPHPMaxSize(version) {
});
}
function phpPreload(version){
phpPost('app_start',version,{},function(data){
onlineEditFile(0, data['data']);
});
}
function getFpmConfig(version){
phpPost('get_fpm_conf', version, {}, function(data){
function phpOpcacheBlacklist(version){
phpPost('opcache_blacklist_file',version,{},function(data){
onlineEditFile(0, data['data']);
});
}
function phpFpmRoot(version){
phpPost('get_fpm_file',version,{},function(data){
onlineEditFile(0, data['data']);
});
}
function phpFpmConfigFile(version, func, pool = 'www'){
var _name = 'php';
if ( typeof(version) == 'undefined' ){
version = '';
}
var func_name = 'conf';
if ( typeof(func) != 'undefined' ){
func_name = func;
}
var poolSelect = "<select class='bt-input-text' name='pool' style='width:100px;'>\
<option value='www' " + (pool == 'www' ? 'selected' : '') + ">www</option>\
<option value='backup' " + (pool == 'backup' ? 'selected' : '') + ">backup</option>\
</select>";
var con = '<p style="color: #666; margin-bottom: 7px">提示:Ctrl+F 搜索关键字,Ctrl+G 查找下一个,Ctrl+S 保存,Ctrl+Shift+R 查找替换!</p>\
<textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
<button id="onlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">保存</button>\
'+poolSelect+'\
<ul class="help-info-text c7 ptb15">\
<li>此处为'+ _name + version +'应用池配置文件,若您不了解配置规则,请勿随意修改。</li>\
</ul>';
var loadT = layer.msg('配置文件路径获取中...',{icon:16,time:0,shade: [0.3, '#000']});
var request_data = {name:_name, func:func_name,version:version};
request_data['args'] = JSON.stringify({'pool':pool});
$.post('/plugins/run', request_data, function (data) {
layer.close(loadT);
try{
var jdata = $.parseJSON(data.data);
if (!jdata['status']){
layer.msg(jdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
}catch(err){/*console.log(err);*/}
$(".soft-man-con").html(con);
var loadT2 = layer.msg('文件内容获取中...',{icon:16,time:0,shade: [0.3, '#000']});
var fileName = data.data;
$.post('/files/get_body', 'path=' + fileName, function(rdata) {
layer.close(loadT2);
if (!rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$("#textBody").empty().text(rdata.data.data);
$(".CodeMirror").remove();
var editor = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-Space": "autocomplete",
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
}
},
lineNumbers: true,
matchBrackets:true,
});
editor.focus();
$(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0});
$("#onlineEditFileBtn").click(function(){
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
});
},'json');
$('select[name="pool"]').change(function(){
var pool = $(this).val();
phpFpmConfigFile(version, func, pool);
});
},'json');
}
function getFpmConfig(version, pool = 'www'){
phpPost('get_fpm_conf', version, {'pool':pool}, function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
// console.log(rdata);
@@ -188,14 +287,19 @@ function getFpmConfig(version){
"<option value='3' " + (rdata.max_children == 100 ? 'selected' : '') + ">100并发</option>" +
"<option value='4' " + (rdata.max_children == 200 ? 'selected' : '') + ">200并发</option>" +
"<option value='5' " + (rdata.max_children == 300 ? 'selected' : '') + ">300并发</option>" +
"<option value='5' " + (rdata.max_children == 500 ? 'selected' : '') + ">500并发</option>" +
"<option value='6' " + (rdata.max_children == 2000 ? 'selected' : '') + ">2000并发</option>";
"<option value='6' " + (rdata.max_children == 500 ? 'selected' : '') + ">500并发</option>" +
"<option value='7' " + (rdata.max_children == 2000 ? 'selected' : '') + ">2000并发</option>";
var pms = [{ 'name': 'static', 'title': '静态' }, { 'name': 'dynamic', 'title': '动态' },{ 'name': 'ondemand', 'title': '按需' }];
var pmList = '';
for (var i = 0; i < pms.length; i++) {
pmList += '<option value="' + pms[i].name + '" ' + ((pms[i].name == rdata.pm) ? 'selected' : '') + '>' + pms[i].title + '</option>';
}
var poolHtml = "<option value='www' " + (pool == 'www' ? 'selected' : '') + ">www</option>" +
"<option value='backup' " + (pool == 'backup' ? 'selected' : '') + ">backup</option>";
var body = "<div class='bingfa'>" +
"<p class='line'><span class='span_tit'>应用池[pool]:</span><select class='bt-input-text' name='pool' style='width:100px;'>" + poolHtml + "</select></p>" +
"<p class='line'><span class='span_tit'>并发方案:</span><select class='bt-input-text' name='limit' style='width:100px;'>" + limitList + "</select></p>" +
"<p class='line'><span class='span_tit'>运行模式:</span><select class='bt-input-text' name='pm' style='width:100px;'>" + pmList + "</select><span class='c9'>*PHP-FPM运行模式</span></p>" +
"<p class='line'><span class='span_tit'>max_children:</span><input class='bt-input-text' type='number' name='max_children' value='" + rdata.max_children + "' /><span class='c9'>*允许创建的最大子进程数</span></p>" +
@@ -248,6 +352,7 @@ function getFpmConfig(version){
start_servers = 35;
min_spare_servers = 35;
max_spare_servers = 250;
break;
case '7':
max_children = 2000;
start_servers = 40;
@@ -261,11 +366,17 @@ function getFpmConfig(version){
$("input[name='min_spare_servers']").val(min_spare_servers);
$("input[name='max_spare_servers']").val(max_spare_servers);
});
$('select[name="pool"]').change(function(){
var pool = $(this).val();
getFpmConfig(version, pool);
});
});
}
function setFpmConfig(version){
var max_children = Number($("input[name='max_children']").val());
var pool = $("select[name='pool']").val();
var start_servers = Number($("input[name='start_servers']").val());
var min_spare_servers = Number($("input[name='min_spare_servers']").val());
var max_spare_servers = Number($("input[name='max_spare_servers']").val());
@@ -303,6 +414,7 @@ function setFpmConfig(version){
min_spare_servers:min_spare_servers,
max_spare_servers:max_spare_servers,
pm:pm,
pool:pool,
};
phpPost('set_fpm_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
@@ -311,14 +423,15 @@ function setFpmConfig(version){
}
function getFpmStatus(version){
phpPost('get_fpm_status', version, '', function(ret_data){
function getFpmStatus(version, pool = 'www'){
phpPost('get_fpm_status', version, {'pool':pool}, function(ret_data){
var tmp_data = $.parseJSON(ret_data.data);
if(!tmp_data.status){
layer.msg(tmp_data.msg, { icon: tmp_data.status ? 1 : 2 });
return;
}
var rdata = tmp_data.data;
var php_fpm_status = '动态';
if (rdata['process manager'] == 'dynamic'){
php_fpm_status = '动态';
@@ -328,8 +441,23 @@ function getFpmStatus(version){
php_fpm_status = '按需';
}
var rdata = tmp_data.data;
var con = "<div style='height:420px;overflow:hidden;'><table class='table table-hover table-bordered GetPHPStatus' style='margin:0;padding:0'>\
var select_pool_www = '';
var select_pool_backup = '';
if (pool == 'www'){
select_pool_www = 'selected';
}
if (pool == 'backup'){
select_pool_backup = 'selected';
}
var con = "<div style='height:430px;'>\
<p style='text-align:center;padding-bottom:10px;'>\
<select class='bt-input-text' name='pool' style='width:200px;'>\
<option value='www' "+select_pool_www+">www</option>\
<option value='backup' "+select_pool_backup+">backup</option>\
</select>\
</p>\
<table class='table table-hover table-bordered get_fpm_status' style='margin:0;padding:0'>\
<tr><th>应用池(pool)</th><td>" + rdata.pool + "</td></tr>\
<tr><th>进程管理方式(process manager)</th><td>" + php_fpm_status + "</td></tr>\
<tr><th>启动日期(start time)</th><td>" + rdata['start time'] + "</td></tr>\
@@ -343,9 +471,16 @@ function getFpmStatus(version){
<tr><th>最大活跃进程数量(max active processes)</th><td>" + rdata['max active processes'] + "</td></tr>\
<tr><th>到达进程上限次数(max children reached)</th><td>" + rdata['max children reached'] + "</td></tr>\
<tr><th>慢请求数量(slow requests)</th><td>" + rdata['slow requests'] + "</td></tr>\
</table></div>";
</table>\
</div>";
$(".soft-man-con").html(con);
$(".GetPHPStatus td,.GetPHPStatus th").css("padding", "7px");
$(".get_fpm_status td,.get_fpm_status th").css("padding", "7px");
$('select[name="pool"]').change(function(){
var pool = $(this).val();
getFpmStatus(version, pool);
});
});
}
@@ -559,10 +694,10 @@ function setDisableFunc(version, act, fs) {
//phpinfo
function getPhpinfo(version) {
var con = '<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button>';
$(".soft-man-con").html(con);
}
// function getPhpinfo(version) {
// var con = '<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">查看phpinfo()</button>';
// $(".soft-man-con").html(con);
// }
//获取PHPInfo
function getPHPInfo_old(version) {
+2 -2
View File
@@ -18,7 +18,7 @@ LOCAL_ADDR=common
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
LOCAL_ADDR=cn
HTTP_PREFIX="https://ghproxy.com/"
HTTP_PREFIX="https://mirror.ghproxy.com/"
fi
if [ ! -d ${SERVER_ROOT}/icu ];then
@@ -27,7 +27,7 @@ if [ ! -d ${SERVER_ROOT}/icu ];then
if [ "$LOCAL_ADDR" == 'cn' ];then
if [ ! -f ${SOURCE_ROOT}/icu4c-52_2-src.tgz ];then
wget --no-check-certificate -O ${SOURCE_ROOT}/icu4c-52_2-src.tgz https://dl.midoks.me/lib/icu4c-52_2-src.tgz -T 20
wget --no-check-certificate -O ${SOURCE_ROOT}/icu4c-52_2-src.tgz https://dl.midoks.icu/lib/icu4c-52_2-src.tgz -T 20
fi
fi
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
# cd /www/server/mdserver-web/plugins/php/lib && bash libedit.sh
# echo $rootPath
SERVER_ROOT=$rootPath/lib
SOURCE_ROOT=$rootPath/source/lib
# LOCAL_ADDR=common
# cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
# if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
# LOCAL_ADDR=cn
# fi
if [ ! -d ${SERVER_ROOT}/libedit ];then
cd $SOURCE_ROOT
VERSION="20230828-3.1"
if [ ! -f ${SOURCE_ROOT}/libedit-${VERSION}.tar.gz ];then
wget --no-check-certificate -O ${SOURCE_ROOT}/libedit-${VERSION}.tar.gz https://thrysoee.dk/editline/libedit-${VERSION}.tar.gz
fi
if [ ! -d ${SOURCE_ROOT}/libedit-${VERSION} ];then
cd $SOURCE_ROOT && tar -zxvf libedit-${VERSION}.tar.gz
fi
cd ${SOURCE_ROOT}/libedit-${VERSION}
./configure --prefix=${SERVER_ROOT}/libedit && make && make install
if [ -d $SOURCE_ROOT/libedit-${VERSION} ];then
cd $SOURCE_ROOT && rm -rf $SOURCE_ROOT/libedit-${VERSION}
fi
fi
+5 -3
View File
@@ -8,6 +8,8 @@ rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
# cd /www/server/mdserver-web/plugins/php/lib && bash libiconv.sh
# echo $rootPath
SERVER_ROOT=$rootPath/lib
@@ -18,7 +20,7 @@ LOCAL_ADDR=common
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
LOCAL_ADDR=cn
HTTP_PREFIX="https://ghproxy.com/"
HTTP_PREFIX="https://mirror.ghproxy.com/"
fi
if [ ! -d ${SERVER_ROOT}/libiconv ];then
@@ -26,12 +28,12 @@ if [ ! -d ${SERVER_ROOT}/libiconv ];then
if [ "$LOCAL_ADDR" == 'cn' ];then
if [ ! -f ${SOURCE_ROOT}/libiconv-1.15.tar.gz ];then
wget --no-check-certificate -O ${SOURCE_ROOT}/libiconv-1.15.tar.gz https://dl.midoks.me/lib/libiconv-1.15.tar.gz -T 20
wget --no-check-certificate -O ${SOURCE_ROOT}/libiconv-1.15.tar.gz https://dl.midoks.icu/lib/libiconv-1.15.tar.gz -T 20
fi
fi
if [ ! -f ${SOURCE_ROOT}/libiconv-1.15.tar.gz ];then
wget --no-check-certificate -O ${SOURCE_ROOT}/libiconv-1.15.tar.gz https:/github.com/midoks/mdserver-web/releases/download/init/libiconv-1.15.tar.gz -T 5
wget --no-check-certificate -O ${SOURCE_ROOT}/libiconv-1.15.tar.gz https://github.com/midoks/mdserver-web/releases/download/init/libiconv-1.15.tar.gz -T 5
fi
if [ ! -d ${SOURCE_ROOT}/libiconv-1.15 ];then

Some files were not shown because too many files have changed in this diff Show More