Compare commits

..
845 Commits
Author SHA1 Message Date
Mr Chen 85fc333d2c Merge pull request #424 from midoks/dev
0.15.1
2023-07-15 23:04:39 +08:00
midoks 5bc27a4725 Update config_api.py 2023-07-15 22:53:38 +08:00
midoks e5acf206f5 Update cli.sh 2023-07-15 20:43:13 +08:00
midoks ae7afc2eb5 Update rhel.sh 2023-07-15 20:34:46 +08:00
midoks 5c8527a5de 监控页面-自定义时间优化。 2023-07-15 19:33:17 +08:00
midoks 274592229e Update rhel.sh 2023-07-15 15:51:03 +08:00
midoks 60ddb13f8e Update rhel.sh 2023-07-15 15:50:35 +08:00
midoks f62af00fb7 Update rhel.sh 2023-07-15 15:49:28 +08:00
midoks 9c6faefffd Update rhel.sh 2023-07-15 15:38:14 +08:00
midoks c9e27c2add 优化
* [插件]docker - 添加IP地址池。
* PHP下载中国优化。
2023-07-15 15:00:00 +08:00
midoks 97b1e8b9b3 Update rhel.sh 2023-07-15 12:34:47 +08:00
midoks 18cdcd1436 修复子目录绑定-伪静态问题。 2023-07-13 10:36:16 +08:00
midoks 7d783c64b6 OP防火墙优化
站点配置-状态关闭后,不再防御。
2023-07-13 00:40:46 +08:00
midoks 0b65d69750 Update __init__.py 2023-07-12 22:18:55 +08:00
midoks 693dbb8cf1 Update __init__.py 2023-07-12 22:17:58 +08:00
midoks 117a99e729 增加标识 2023-07-12 09:46:58 +08:00
midoks 45d4b8a5de update 2023-07-11 16:25:34 +08:00
midoks a5791051b1 Update debian.sh 2023-07-11 16:11:20 +08:00
midoks dc3f8f8e0b 自动同步gitee 2023-07-11 12:21:48 +08:00
midoks bf1d00c012 Update config_api.py 2023-07-10 22:41:13 +08:00
midoks 51cf851cea Update site.js 2023-07-10 22:38:37 +08:00
midoks 1e09408eb9 Update index.py 2023-07-10 22:13:46 +08:00
midoks 7659865caf Update lib.sh 2023-07-05 22:19:44 +08:00
Mr Chen ad1851d068 Merge pull request #423 from midoks/dev
requests兼容低版本
2023-07-05 18:05:33 +08:00
midoks e174652afc Update requirements.txt 2023-07-05 18:02:40 +08:00
midoks a95e7aacd7 Update r3.6.txt 2023-07-05 18:00:36 +08:00
Mr Chen 6aa638ef9a Merge pull request #422 from midoks/dev
Update requirements.txt
2023-07-05 13:03:14 +08:00
midoks 6f3d50bae5 Update requirements.txt 2023-07-05 13:01:08 +08:00
Mr Chen 301a5a95b8 Merge pull request #421 from midoks/dev
AD
2023-07-05 12:51:37 +08:00
midoks d35b9dccc7 AD信息 2023-07-05 12:49:47 +08:00
midoks 82680605ac mvirtua ad 2023-07-05 12:47:05 +08:00
midoks 5b148b3d1a Update requirements.txt 2023-07-05 10:20:04 +08:00
Mr Chen 714acd20e5 Merge pull request #420 from midoks/dev
0.15.0
2023-07-04 20:55:21 +08:00
midoks bf58cd8acc Update config_api.py 2023-07-04 20:52:57 +08:00
midoks 059053d27c mysql安装成功后,删除原文件 2023-07-03 22:22:11 +08:00
midoks 185e73c26a Update index.py 2023-07-03 22:12:55 +08:00
midoks 569511d321 update 2023-07-03 22:08:00 +08:00
midoks f88bf5059f Update README.md 2023-07-03 17:52:56 +08:00
midoks 05b63b8d2b Update index.py 2023-07-03 17:45:12 +08:00
midoks 3a197b273d Update docker.js 2023-07-03 17:37:14 +08:00
midoks f4fdbab41c Update index.py 2023-07-03 17:35:34 +08:00
midoks f6b2940657 docker插件容器创建OK 2023-07-03 17:34:58 +08:00
midoks 78b9ac5df0 up 2023-07-03 11:53:54 +08:00
midoks 3ea4272307 Update docker.js 2023-07-02 16:29:10 +08:00
midoks efc7cee9ad Update docker.js 2023-07-02 15:36:38 +08:00
midoks 5c4805453d Update docker.js 2023-07-02 15:27:25 +08:00
midoks f6da241c85 update 2023-07-02 14:38:56 +08:00
midoks d5b6eb2325 update 2023-07-01 22:06:54 +08:00
midoks 6ed2cddf71 Update docker.js 2023-07-01 21:35:46 +08:00
midoks 9c31d76442 docker update 2023-07-01 21:34:04 +08:00
midoks 7aecbaf7df Update docker.js 2023-07-01 15:22:41 +08:00
midoks ee81a86d24 update 2023-07-01 15:17:43 +08:00
midoks 0a60d66732 update 2023-07-01 14:46:22 +08:00
midoks c3e3cff472 Update docker.js 2023-07-01 12:37:15 +08:00
midoks 194d46eb6a Update docker.js 2023-07-01 12:37:02 +08:00
midoks d66bc94edc Update docker.js 2023-07-01 12:34:09 +08:00
midoks fb4ffcd343 Update index.py 2023-07-01 12:30:58 +08:00
midoks 10c235e317 Update r3.6.txt 2023-07-01 12:25:32 +08:00
midoks 9c156928d8 up 2023-07-01 12:24:04 +08:00
midoks 771905d7f6 Update requirements.txt 2023-07-01 12:23:01 +08:00
midoks cd21b3f3e7 Update r3.6.txt 2023-07-01 12:22:18 +08:00
midoks 982026db24 update 2023-07-01 12:21:07 +08:00
midoks f9b91d9989 Update docker.js 2023-07-01 12:17:30 +08:00
midoks f7b1159bd7 update 2023-07-01 12:15:51 +08:00
midoks 6aa49ddbcf Update rhel.sh 2023-07-01 11:48:06 +08:00
midoks 866eddac1d Update lib.sh 2023-07-01 10:19:42 +08:00
midoks af0cce4216 Update install.sh 2023-07-01 10:16:39 +08:00
midoks 3951322d86 Update install_dev.sh 2023-07-01 10:16:23 +08:00
midoks dfdd16b444 Update index.py 2023-07-01 10:11:15 +08:00
midoks aa8fec2b7e update 2023-07-01 09:52:53 +08:00
midoks 2a8958ab84 Update index.py 2023-07-01 00:32:36 +08:00
midoks f5125670ee Update index.py 2023-07-01 00:19:24 +08:00
midoks 2a8d4fb7a9 Update requirements.txt 2023-07-01 00:14:04 +08:00
midoks 59f7fe2290 Update requirements.txt 2023-07-01 00:07:30 +08:00
midoks 928db6e7e7 Update requirements.txt 2023-07-01 00:02:13 +08:00
midoks f3927bd6cf Update requirements.txt 2023-07-01 00:01:32 +08:00
midoks bb92727b56 Update requirements.txt 2023-07-01 00:00:14 +08:00
midoks 21b80b1fce Update index.py 2023-06-30 23:54:05 +08:00
midoks 637da92834 up 2023-06-30 23:43:51 +08:00
midoks f5859626a9 update 2023-06-30 21:57:42 +08:00
midoks 003449eb0a update 2023-06-30 12:30:28 +08:00
midoks d27f926191 update 2023-06-30 12:16:25 +08:00
midoks 7483247d4d up 2023-06-30 10:17:02 +08:00
midoks 1ad841d3af Update docker.js 2023-06-30 00:09:15 +08:00
midoks 27376d879c up 2023-06-30 00:09:09 +08:00
midoks 8b824447c1 Update php.service.tpl 2023-06-29 18:29:39 +08:00
midoks a1d26dcd45 Update intl.sh 2023-06-29 16:25:12 +08:00
midoks 5e68c7bf0a Update install.sh 2023-06-29 13:00:08 +08:00
midoks 481ae16713 Update index.py 2023-06-29 12:59:05 +08:00
midoks 2d2bd39f9e Update intl.sh 2023-06-29 12:02:48 +08:00
midoks 7246a878a5 Update intl.sh 2023-06-29 12:00:37 +08:00
midoks 542ee3cdb0 Update intl.sh 2023-06-29 11:59:59 +08:00
midoks 69503b223b update 2023-06-29 11:43:56 +08:00
midoks 78d8fa7ebf Update lib.sh 2023-06-29 10:54:26 +08:00
midoks 21e9d8f2d8 Update update_dev.sh 2023-06-29 10:49:10 +08:00
midoks 3c6adfbd44 Update install.sh 2023-06-29 10:41:10 +08:00
midoks c0e70abe6d Update install_dev.sh 2023-06-29 10:40:31 +08:00
midoks f174e71228 Update app.py 2023-06-29 10:25:14 +08:00
midoks 7a9a811ea6 Update app.py 2023-06-29 10:21:39 +08:00
midoks c7e3d9d9a3 Update app.py 2023-06-29 10:20:39 +08:00
midoks 161f7a1bc0 Update app.py 2023-06-29 10:18:52 +08:00
midoks 175cce0131 Update lib.sh 2023-06-29 10:11:52 +08:00
midoks 3735897ed2 Update lib.sh 2023-06-29 09:59:06 +08:00
midoks 30bfa5a630 Update lib.sh 2023-06-29 09:56:24 +08:00
midoks 594fdb4712 Update lib.sh 2023-06-29 09:55:14 +08:00
midoks 31a441ea02 update 2023-06-29 09:52:30 +08:00
midoks 06f7087fad Update requirements.txt 2023-06-29 09:30:06 +08:00
midoks e7b8f5afdc Update index.py 2023-06-29 09:25:55 +08:00
midoks 6b57addfa7 Update index.py 2023-06-28 19:11:44 +08:00
midoks aea435fbaf Update index.py 2023-06-28 18:53:45 +08:00
midoks 9cd6656946 u 2023-06-28 16:04:17 +08:00
midoks 4f7df4b3c3 Update index.py 2023-06-28 14:58:45 +08:00
midoks 70d12b7b8d docker 2023-06-28 14:53:59 +08:00
midoks fe576c820a Update requirements.txt 2023-06-28 04:09:09 +08:00
midoks b48a53e0d7 Create nezha.conf 2023-06-28 04:04:44 +08:00
midoks 4701839c33 up 2023-06-28 03:40:23 +08:00
midoks 916bc67c4d Update cert_api.py 2023-06-28 03:21:11 +08:00
midoks d7bba830cc Update requirements.txt 2023-06-28 02:33:11 +08:00
midoks 7a28f8f57a Update index.py 2023-06-28 02:30:28 +08:00
midoks 41ee25aa7b update 2023-06-28 02:21:59 +08:00
midoks c8aa91cfa3 up 2023-06-28 02:09:28 +08:00
midoks 98f27498b0 Update index.py 2023-06-28 01:57:06 +08:00
midoks 5444fe6455 Update index.py 2023-06-28 01:40:41 +08:00
midoks 9627c6e47b Update index.py 2023-06-28 01:32:14 +08:00
midoks 13597d6282 Update index.py 2023-06-28 01:21:15 +08:00
midoks d09494e3aa Update index.py 2023-06-28 01:14:15 +08:00
midoks d35439d286 Update index.py 2023-06-28 01:14:03 +08:00
midoks ced48bab47 nezha 测试OK 2023-06-28 01:02:58 +08:00
midoks fe2df6cc8d up 2023-06-28 00:08:38 +08:00
midoks 8bdfe15101 nezha 60% 2023-06-28 00:04:07 +08:00
midoks 42e9983b88 Update config.json 2023-06-27 15:56:43 +08:00
midoks 9b7c0b6f99 up 2023-06-27 15:11:38 +08:00
midoks e421292c9e up 2023-06-27 14:13:04 +08:00
midoks 7b4d31779a Update install.sh 2023-06-27 01:31:52 +08:00
midoks f3b09056f3 init nezha plugin 2023-06-26 23:06:06 +08:00
midoks a92ccea6c5 lrzsz 2023-06-26 11:57:07 +08:00
midoks 9da77a0a9b up 2023-06-24 22:37:02 +08:00
midoks c233ecaaa7 up 2023-06-22 16:06:04 +08:00
midoks 5828b8b8cb up 2023-06-22 16:00:09 +08:00
midoks a4a1a2c83c up 2023-06-20 16:39:36 +08:00
midoks 0e20bc182c up 2023-06-19 20:28:44 +08:00
midoks 99c0b0a81a Update site_api.py 2023-06-17 23:20:24 +08:00
midoks 3fa199fec4 acme部署问题 2023-06-17 23:18:15 +08:00
midoks 194c36c6d8 tg ad 2023-06-15 01:43:21 +08:00
midoks 2fb542f6b4 Update all_test.sh 2023-06-14 01:25:55 +08:00
midoks 60af43ed31 Update intl.sh 2023-06-14 01:24:15 +08:00
midoks 9f02cf9744 Update install.sh 2023-06-14 01:21:47 +08:00
midoks 846bd270df Update yaf.sh 2023-06-14 01:14:47 +08:00
midoks d910d4f462 up 2023-06-14 00:31:20 +08:00
midoks 13f5b1bf02 up 2023-06-13 18:34:57 +08:00
midoks 1fc3fd6247 Update lib.sh 2023-06-13 18:03:53 +08:00
midoks 36e3feb886 Update requirements.txt 2023-06-13 17:46:00 +08:00
midoks 0ca34afacd Update lib.sh 2023-06-13 17:43:39 +08:00
midoks ffb3288f3d Update requirements.txt 2023-06-13 17:40:55 +08:00
midoks e2f68a73ed Update requirements.txt 2023-06-13 17:34:23 +08:00
midoks 92fa8da2f6 Update lib.sh 2023-06-13 17:19:23 +08:00
midoks 7c96ddd63e Update lib.sh 2023-06-13 17:14:50 +08:00
midoks c4e7872179 Update lib.sh 2023-06-13 17:14:31 +08:00
midoks d399cb2bb4 Update install.sh 2023-06-13 16:38:04 +08:00
midoks 985cbc7eca Update install.sh 2023-06-13 16:36:48 +08:00
midoks 27ed21a17d update 2023-06-10 15:09:31 +08:00
midoks 972165ba1a Update lib.sh 2023-05-30 17:53:16 +08:00
midoks e76eb4d0e8 Update client_check_member.py 2023-05-29 18:40:12 +08:00
midoks fd05c40dbb up 2023-05-29 18:34:37 +08:00
midoks a1a7fa5c82 网站备注优化 2023-05-28 19:59:31 +08:00
midoks 531de1407f Update push_notice_msg.py 2023-05-28 19:00:42 +08:00
midoks ca455f13e8 ad 2023-05-28 14:50:53 +08:00
midoks ab5342b01f Update docker.js 2023-05-27 00:18:44 +08:00
midoks a5a57c5718 update 2023-05-27 00:18:39 +08:00
midoks 27999b21e6 Update config.json 2023-05-24 23:04:59 +08:00
midoks d2c6caeef2 Update client_temp.py 2023-05-23 20:46:32 +08:00
midoks de30d8a41f Create client_temp.py 2023-05-23 20:42:08 +08:00
midoks d3abc8e7b2 up 2023-05-18 17:10:50 +08:00
midoks b7aad65eb5 Update site_api.py 2023-05-17 13:36:35 +08:00
midoks 240b1dec27 修正网站搜索功能 2023-05-16 20:34:12 +08:00
midoks 4756e0f68b Update push_notice_msg.py 2023-05-15 19:30:38 +08:00
midoks 59f62b948a Update push_notice_msg.py 2023-05-15 19:30:00 +08:00
midoks 0ab0741031 up 2023-05-15 19:23:32 +08:00
midoks 2fd2f6e844 AD 2023-05-15 19:20:58 +08:00
midoks e534c6177a update 2023-05-15 19:14:43 +08:00
midoks 897c6322fc Update install.sh 2023-05-14 23:57:41 +08:00
midoks 201e93f946 Update requirements.txt 2023-05-14 19:09:02 +08:00
Mr Chen a78fd957ec Merge pull request #411 from midoks/dev
更新pip库2
2023-05-14 19:05:30 +08:00
midoks 3ce037b0a1 Update requirements.txt 2023-05-14 19:03:39 +08:00
midoks f3176340f8 Update requirements.txt 2023-05-14 19:02:58 +08:00
midoks 7bfe096e8d Update requirements.txt 2023-05-14 19:00:45 +08:00
Mr Chen 066428fca8 Merge pull request #410 from midoks/dev
更新pip版本
2023-05-14 18:46:51 +08:00
midoks a1313846c8 Update requirements.txt 2023-05-14 18:43:47 +08:00
midoks 0433123abd Update requirements.txt 2023-05-14 18:36:50 +08:00
midoks 72e99844dd Update requirements.txt 2023-05-14 18:31:19 +08:00
Mr Chen 3a7882e7fa Merge pull request #409 from midoks/dev
0.14.5
2023-05-14 13:12:27 +08:00
midoks bec2a9a12c 0.14.5
* 软件管理-搜索功能。
* 文件-右键功能优化。
2023-05-14 13:10:17 +08:00
midoks 8f02363782 Update files.html 2023-05-12 11:22:38 +08:00
midoks 939c847f3e Update plugins_api.py 2023-05-10 18:23:06 +08:00
midoks a623039db7 完成搜索功能 2023-05-10 18:20:48 +08:00
midoks b7f49a1839 Update soft.html 2023-05-10 17:59:17 +08:00
midoks f1f60870f6 up 2023-05-09 12:46:09 +08:00
midoks 3b04739fd4 up 2023-05-09 12:45:25 +08:00
midoks fdf1e0b0be up 2023-05-09 12:39:44 +08:00
midoks d3385f526f Update client_check_member.py 2023-05-09 11:37:39 +08:00
midoks 20f9095b93 up 2023-05-09 09:17:54 +08:00
midoks 757cf483a2 Update client_ad.py 2023-05-08 12:07:36 +08:00
midoks 1712cfd024 Update client_ad.py 2023-05-08 12:03:16 +08:00
midoks 2b524cbe75 Update client_ad.py 2023-05-08 11:57:01 +08:00
midoks 607d384000 Update client_ad.py 2023-05-08 11:29:09 +08:00
midoks 14cdc7b82e Update client_ad.py 2023-05-08 11:15:27 +08:00
midoks c3219bcba2 Update client_check_member.py 2023-05-07 23:15:06 +08:00
Mr Chen a12c4dd78e Merge pull request #407 from midoks/dev
0.14.4
2023-05-06 14:54:52 +08:00
midoks 39c6f19592 Update README.md 2023-05-06 14:54:34 +08:00
midoks f18c05a097 0.14.4 2023-05-06 14:53:16 +08:00
midoks 80f296ea19 redat 系列 php74之后都需要安装oniguruma
debian系统,不需要
2023-05-06 14:42:54 +08:00
midoks b3e9283a58 Update rhel.sh 2023-05-06 14:37:25 +08:00
midoks 2e140a3ae1 Update index.py 2023-05-06 14:18:46 +08:00
midoks 4d733c8886 Update index.py 2023-05-06 14:16:50 +08:00
midoks 62a7320baf Update rhel.sh 2023-05-06 13:59:02 +08:00
midoks 3dc7c2f5c1 Update rhel.sh 2023-05-06 13:52:55 +08:00
midoks fe62bbee06 Update rhel.sh 2023-05-06 13:24:47 +08:00
midoks f7c0cd82a0 Update rhel.sh 2023-05-06 13:22:49 +08:00
midoks 13a2014558 Update rhel.sh 2023-05-06 12:49:25 +08:00
midoks 5981f94376 Update rhel.sh 2023-05-06 12:30:51 +08:00
midoks 005e0f1513 Update rhel.sh 2023-05-06 12:27:54 +08:00
midoks 63a0f0fbdc Update rhel.sh 2023-05-05 23:32:07 +08:00
midoks edc0be11a1 Update rhel.sh 2023-05-05 23:22:22 +08:00
midoks 908b6e67c6 Update rhel.sh 2023-05-05 23:21:57 +08:00
midoks dfe46332db up 2023-05-05 22:49:39 +08:00
midoks fcdf2e18b2 Update config_api.py 2023-05-05 22:19:33 +08:00
midoks 3c8f9bcf96 Update config.js 2023-05-05 22:19:26 +08:00
midoks ebadd6d80d 端口修改后,跳转优化 2023-05-05 22:16:53 +08:00
Mr Chen 6062699074 Merge pull request #406 from midoks/dev
0.14.3
2023-05-05 20:52:04 +08:00
midoks df9d57ba70 Update README.md 2023-05-05 20:50:20 +08:00
midoks ffca953539 up 2023-05-05 20:49:45 +08:00
midoks bd4946124f Update install.sh 2023-05-05 18:21:10 +08:00
midoks 8e18c63cee up 2023-05-05 17:52:13 +08:00
midoks d201ca2574 Update install_dev.sh 2023-05-05 17:51:09 +08:00
midoks b644f91090 安装时curl库软连接修复 2023-05-05 16:59:47 +08:00
midoks 931f51cf59 Update client_ad.py 2023-05-05 14:12:14 +08:00
midoks 0909a11fd9 Update client_ad.py 2023-05-05 14:03:45 +08:00
midoks 2ba2833699 Update client_ad.py 2023-05-05 13:59:14 +08:00
midoks 20389263fb Update client_ad.py 2023-05-04 20:41:10 +08:00
midoks 86141ccf3a Update my5.7.cnf 2023-05-04 16:42:59 +08:00
midoks b2fdf84ca0 Update index.py 2023-05-04 16:39:46 +08:00
midoks 8fbc456e1a Update my5.7.cnf 2023-05-04 13:19:21 +08:00
midoks 4e43382496 Update client_ad.py 2023-05-03 18:29:37 +08:00
midoks 0326d4f112 Update client_ad.py 2023-05-03 18:05:33 +08:00
midoks a87c13c5e0 Update client_ad.py 2023-05-03 13:02:21 +08:00
midoks 5f3720c855 Update client_ad.py 2023-05-03 12:50:41 +08:00
midoks f548e020c4 up 2023-05-03 12:33:56 +08:00
midoks 7f21781c0b Update tgclient.py 2023-05-03 12:33:01 +08:00
midoks 680b0f09f2 Update client_ad.py 2023-05-03 12:22:31 +08:00
midoks 482943a63c Update client_ad.py 2023-05-03 10:53:49 +08:00
midoks 2871aee18e Create client_ad.py 2023-05-03 10:53:18 +08:00
midoks ff46d9b36e up 2023-05-02 21:39:18 +08:00
midoks fd5fcba543 up 2023-05-02 13:25:07 +08:00
Mr Chen fe04e02e88 Merge pull request #405 from midoks/dev
0.14.2
2023-05-02 12:11:48 +08:00
midoks 93554332a7 Update README.md 2023-05-02 12:10:37 +08:00
midoks b541c7e1b7 Update config_api.py 2023-05-02 12:09:02 +08:00
midoks 1dec1a286a Update docker.js 2023-05-02 12:07:51 +08:00
midoks b17510104d up 2023-05-02 11:55:32 +08:00
midoks c2c8ea0ce6 Update install.sh 2023-05-02 11:52:56 +08:00
midoks acbdb013ae Update install.sh 2023-05-02 11:42:16 +08:00
midoks b025f21765 Update index.py 2023-05-02 11:36:28 +08:00
midoks 1afc8a69e5 Update index.py 2023-05-02 11:35:21 +08:00
midoks 743fc9e8d3 Update index.py 2023-05-02 11:35:06 +08:00
midoks 8d692d2b3b Update install.sh 2023-05-02 11:34:00 +08:00
midoks a0b362e691 Update index.py 2023-05-02 11:31:25 +08:00
midoks 98e1c2ae8f Update install.sh 2023-05-02 11:26:27 +08:00
midoks c0e5915285 Update index.html 2023-05-02 11:23:46 +08:00
midoks 667a0fd0fd Update install.sh 2023-05-02 11:19:03 +08:00
midoks 8ed5f283b0 Update client_check_member.py 2023-05-01 17:30:03 +08:00
midoks 643c370d30 up 2023-05-01 17:26:02 +08:00
midoks 4601303065 up 2023-05-01 16:05:54 +08:00
midoks 14940d6734 Delete mdioks.session 2023-05-01 15:09:14 +08:00
midoks fdc2b0f5c4 Update client_holding.py 2023-05-01 15:08:40 +08:00
midoks cf0b233f63 Update client_check_member.py 2023-05-01 14:51:54 +08:00
midoks b3a7ef2206 Create client_holding.py 2023-05-01 14:49:50 +08:00
midoks 9a3ca3e833 Update index.html 2023-04-30 10:17:28 +08:00
midoks 9afff8df3f Update index.py 2023-04-30 01:13:00 +08:00
midoks ccd0b06223 Update tgclient.py 2023-04-30 01:04:16 +08:00
midoks 7b495fe9bf Update tgclient.py 2023-04-29 16:24:19 +08:00
midoks 2c3fb75e8f Update tgclient.js 2023-04-29 16:11:09 +08:00
midoks 53b606602f up 2023-04-29 16:10:30 +08:00
midoks ecef0cf994 up 2023-04-29 16:01:10 +08:00
midoks 3691d41b23 Update client_change_username.py 2023-04-28 21:47:13 +08:00
midoks 1f66457a3e Update client_change_username.py 2023-04-28 17:25:38 +08:00
midoks 8e05beccfd Update tgclient.py 2023-04-28 17:22:56 +08:00
midoks 35424eae1f up 2023-04-28 17:21:13 +08:00
midoks ed6df6d527 up 2023-04-28 17:03:41 +08:00
midoks 4366c4afde Update tgclient.py 2023-04-24 22:05:34 +08:00
midoks 4bb059f62f Update info.json 2023-04-24 21:23:44 +08:00
midoks aa8f618d9c Update tgclient.py 2023-04-24 21:15:47 +08:00
midoks dfd753e4c1 up 2023-04-24 21:07:25 +08:00
midoks e38daf3c89 Update tgclient.py 2023-04-24 20:51:54 +08:00
midoks 535838fc5e Update tgclient.py 2023-04-24 20:44:28 +08:00
midoks 797853bd61 Update tgclient.py 2023-04-24 20:36:49 +08:00
midoks 0de3aff045 up 2023-04-24 20:32:41 +08:00
midoks 0b7b48ab23 up 2023-04-24 20:31:31 +08:00
midoks 5ff0a0bfbc Update index.py 2023-04-21 21:03:30 +08:00
midoks 9131f44d67 Update install.sh 2023-04-21 13:02:42 +08:00
midoks 6b86bb9d2b Update docker.js 2023-04-21 13:00:05 +08:00
midoks dc06d6beda Update install.sh 2023-04-21 12:58:50 +08:00
midoks 2c8ea2498e Update install.sh 2023-04-21 12:55:38 +08:00
midoks 6b01173b61 Update push_notice_msg.py 2023-04-20 12:41:56 +08:00
midoks 883c554850 up 2023-04-20 12:19:33 +08:00
midoks d267da351c Update push_ad.py 2023-04-16 23:48:24 +08:00
midoks 13a39f4d6a up 2023-04-16 20:50:30 +08:00
Mr Chen cff1d5ee89 Merge pull request #403 from midoks/dev
0.14.1
2023-04-16 20:42:39 +08:00
midoks bf5274c313 0.14.1
* 安装优化。
* 加入OP负载均衡插件。
* 网站防篡改程序(测试中)。
2023-04-16 20:41:39 +08:00
midoks 5623e3efac Update requirements.txt 2023-04-16 20:38:03 +08:00
midoks b93bb6c64c Update requirements.txt 2023-04-16 20:37:24 +08:00
midoks c9962f169e Update requirements.txt 2023-04-16 20:36:01 +08:00
midoks 080f343ee2 Update push_ad.py 2023-04-15 10:57:19 +08:00
midoks 5aeaf13f16 负载均衡插件 2023-04-13 15:42:01 +08:00
midoks 528094cfa7 网站防篡改程序 2023-04-13 15:33:15 +08:00
midoks ed3e3336b2 Update push_notice_msg.py 2023-04-13 15:28:38 +08:00
Mr Chen a75a49c2ae Merge pull request #402 from midoks/dev
0.14.0
2023-04-13 15:21:19 +08:00
midoks 1204e72f41 0.14.0
* 加入系统加固插件。
2023-04-13 15:20:15 +08:00
midoks 13ca5544a5 Update system_safe.tpl 2023-04-13 15:14:32 +08:00
midoks e53fe26d52 Update system_safe.tpl 2023-04-13 15:09:20 +08:00
midoks 13772399f6 Update system_safe.py 2023-04-13 15:05:06 +08:00
midoks 98f11e2662 Update plugins_api.py 2023-04-13 14:49:46 +08:00
midoks f0b0302f75 Update install.sh 2023-04-13 14:42:07 +08:00
midoks 5b9b466cb9 系统加固放出 2023-04-13 14:39:18 +08:00
midoks 5588a11ea5 Update cert_request.py 2023-04-10 22:35:09 +08:00
midoks da05a4ef19 up 2023-04-10 22:34:12 +08:00
midoks 34cf899529 Update mw.py 2023-04-04 12:43:09 +08:00
midoks 0d7d67b012 up 2023-04-04 12:42:47 +08:00
midoks 5b778bfc0d Update vip_api.py 2023-04-04 12:20:28 +08:00
midoks 6ce414cecf up 2023-04-03 22:39:07 +08:00
midoks c8160b63e7 up 2023-04-03 22:30:08 +08:00
midoks 68d957fd6e Update README.md 2023-04-03 19:34:05 +08:00
midoks f09c438500 Update config.html 2023-04-03 17:46:18 +08:00
Mr Chen 9bc9944a3e Merge pull request #401 from midoks/dev
0.13.6
2023-04-03 17:43:58 +08:00
midoks 9e4c2b13d5 Update README.md 2023-04-03 17:43:05 +08:00
midoks cd7143047f 0.13.6
1.修复初始化安装,缺少解压命令。
2.加入aes加密/解密方法
2023-04-03 17:41:48 +08:00
midoks d608ac4d94 Update install.sh 2023-04-03 16:48:53 +08:00
midoks 9fedf9d10d Update push_notice_msg.py 2023-04-01 10:37:33 +08:00
midoks 9936191da2 up 2023-04-01 10:35:54 +08:00
midoks 538eba3acf up 2023-03-31 22:37:40 +08:00
midoks e39ee9a6f7 VIP用户管理 2023-03-30 21:57:33 +08:00
Mr Chen e1820ad5b3 Merge pull request #400 from midoks/dev
0.13.5
2023-03-30 17:31:54 +08:00
midoks 22133f1a6c 0.13.5
### 版本更新 0.13.5

* 添加邮件通知功能。
* 修复初始安装脚本。
2023-03-30 17:30:15 +08:00
midoks 0041cbdff3 添加邮件通知功能 2023-03-30 17:18:40 +08:00
midoks 889da3c769 Update install.sh 2023-03-30 11:59:55 +08:00
midoks d086eb9c61 Update install.sh 2023-03-30 11:56:48 +08:00
midoks 832fa9cd1a Update install_dev.sh 2023-03-30 11:54:40 +08:00
midoks 8c19fb9629 Update config_api.py 2023-03-30 11:22:36 +08:00
midoks a2e4dd6753 Update push_notice_msg.py 2023-03-30 11:22:19 +08:00
midoks 22ba7dda55 Update install.sh 2023-03-29 16:35:09 +08:00
midoks 2ffa36eecb up 2023-03-29 16:32:46 +08:00
Mr Chen fe5843b35d Merge pull request #398 from midoks/dev
修复python pip源安装
2023-03-29 16:27:46 +08:00
midoks e95acbe947 Update lib.sh 2023-03-29 16:08:55 +08:00
midoks aed8319dd3 Update push_ad.py 2023-03-29 14:08:06 +08:00
midoks babe1b885e Update push_notice_msg.py 2023-03-29 13:17:38 +08:00
midoks 0612f52402 Update push_notice_msg.py 2023-03-29 13:03:52 +08:00
midoks db67cea737 AD 2023-03-29 13:01:12 +08:00
midoks 52cf675843 Update install_dev.sh 2023-03-29 08:49:26 +08:00
Mr Chen 3421bf6ab5 Merge pull request #397 from midoks/dev
0.13.4
2023-03-28 23:54:51 +08:00
midoks 2f39bd600b Update config_api.py
### 版本更新 0.13.4

无重大更新

* 国内安装不在依赖gitee。
* tgbot优化。
2023-03-28 23:53:14 +08:00
midoks acd5ec69e8 Update tgbot.py 2023-03-28 23:49:59 +08:00
midoks 09878728af Update push_ad.py 2023-03-28 20:25:09 +08:00
midoks af82e9f129 Update push_notice_msg.py 2023-03-28 20:23:08 +08:00
midoks c74630e738 Update push_notice_msg.py 2023-03-28 20:19:49 +08:00
midoks e4e0697b4b Update push_notice_msg.py 2023-03-28 20:18:52 +08:00
midoks 11b5ac658b Update mw.tpl 2023-03-28 18:00:50 +08:00
midoks 1306731164 up 2023-03-28 17:47:59 +08:00
midoks bb6c933aee Update README.md 2023-03-28 17:41:50 +08:00
midoks d6a93ef1e6 Update info.json 2023-03-28 17:18:59 +08:00
midoks 6610da402a Update info.json 2023-03-28 17:18:47 +08:00
midoks 3ace9cf51e Update install.sh 2023-03-28 16:54:21 +08:00
midoks 49c7ec6073 Update tgbot.py 2023-03-28 16:31:46 +08:00
midoks 8cf526667e up 2023-03-25 22:05:19 +08:00
midoks 6c42876411 Update receive_faq.py 2023-03-25 21:58:08 +08:00
midoks 79471e3806 Update receive_faq.py 2023-03-25 21:56:50 +08:00
midoks cad06425fc Update lib.sh 2023-03-23 15:24:49 +08:00
midoks 6f1e11e474 Update lib.sh 2023-03-23 15:21:22 +08:00
midoks 59d13e50ce Update rhel.sh 2023-03-22 22:26:32 +08:00
midoks 5da0746240 Update push_bbs_ntid.py 2023-03-22 18:00:32 +08:00
midoks 192ea8b029 Update push_bbs_ntid.py 2023-03-22 17:34:18 +08:00
midoks bfc20b3e42 Update push_tmp_msg.py 2023-03-22 17:01:50 +08:00
midoks 56bee5c752 Update push_tmp_msg.py 2023-03-22 16:41:26 +08:00
midoks 312df5de1f Create push_bbs_ntid.py 2023-03-22 16:41:23 +08:00
midoks 4d3640286c Update README.md 2023-03-20 17:49:48 +08:00
midoks 20930806b6 Update install.sh 2023-03-20 12:19:35 +08:00
midoks 71360b61da Update install.sh 2023-03-20 12:04:54 +08:00
midoks 411645c9e2 Update install.sh 2023-03-20 12:01:46 +08:00
midoks 3de4e1bfff up 2023-03-19 00:21:36 +08:00
midoks 34285f6051 Update push_tmp_msg.py 2023-03-19 00:20:23 +08:00
midoks 84f0cda89b up 2023-03-18 18:32:30 +08:00
midoks 04012085ce Update mdw.jpg 2023-03-17 19:18:27 +08:00
midoks 9ad00f3ce7 Update push_tmp_msg.py 2023-03-16 22:36:25 +08:00
midoks 609a4ed351 Update tgbot.py 2023-03-16 21:34:44 +08:00
midoks 5ca74fd312 Update push_tmp_msg.py 2023-03-16 19:22:36 +08:00
midoks 3b1bb06c68 Update push_tmp_msg.py 2023-03-16 18:57:09 +08:00
midoks b6b7de42d6 Update push_tmp_msg.py 2023-03-16 18:53:29 +08:00
midoks 3aa3b532ac Update push_tmp_msg.py 2023-03-16 18:48:19 +08:00
midoks 290c740ab1 Update push_tmp_msg.py 2023-03-16 18:43:02 +08:00
midoks 23fd4ca1de Create push_tmp_msg.py 2023-03-16 18:42:42 +08:00
midoks c128a799b2 Update receive_faq.py 2023-03-16 15:50:52 +08:00
midoks 401c103b76 Update receive_faq.py 2023-03-16 15:47:14 +08:00
midoks 6fb88eb428 Update push_ad.py 2023-03-16 15:33:18 +08:00
midoks 956f20d295 tgbot init命令分离 2023-03-16 15:30:43 +08:00
midoks 03f8578a37 Update README.md 2023-03-16 13:04:29 +08:00
Mr Chen 265e17beac Merge pull request #393 from midoks/dev
0.13.3
2023-03-16 13:00:56 +08:00
midoks f3d83ad8a5 Update README.md 2023-03-16 12:58:06 +08:00
midoks 39b376a7cb Update webstats_common.lua 2023-03-16 12:24:02 +08:00
midoks 07858794ef Update webstats_common.lua 2023-03-16 12:02:33 +08:00
midoks 391473fc14 Update lib.sh 2023-03-15 23:26:23 +08:00
midoks 0993adcc5f Update lib.sh 2023-03-15 23:24:47 +08:00
midoks 90b1d88111 Update lib.sh 2023-03-15 23:17:49 +08:00
midoks 87098cff95 up 2023-03-15 23:00:37 +08:00
midoks e6e64b2a4c Update mysql.js 2023-03-15 22:59:23 +08:00
midoks 81436ea81b Update index.html 2023-03-15 22:57:22 +08:00
midoks cf7d29190d Update index.html 2023-03-15 22:53:36 +08:00
midoks 4ff62ec6ad Update tgbot.py 2023-03-15 22:09:53 +08:00
midoks dac3ccce8d Update tgbot.py 2023-03-15 21:53:41 +08:00
midoks 10bd7aa70f Update tool_migrate.py 2023-03-15 18:28:31 +08:00
midoks dec0afc3d3 Update tool_migrate.py 2023-03-15 18:25:43 +08:00
midoks 2331853b3b Update info.json 2023-03-15 18:13:34 +08:00
midoks b9e063e423 Update README.md 2023-03-15 18:11:35 +08:00
midoks 52294948b2 Update config_api.py 2023-03-15 18:09:20 +08:00
midoks 87bec2b988 Update tgbot.py 2023-03-15 18:06:14 +08:00
midoks 9ab91ecc93 Update index.py 2023-03-15 17:48:05 +08:00
midoks 18312a3596 Update tgbot.py 2023-03-15 17:37:35 +08:00
midoks 8fb35440c8 Update info.json 2023-03-15 17:35:28 +08:00
midoks a874934379 Update receive_faq.py 2023-03-15 17:34:05 +08:00
midoks 2c4e4aea3f Update info.json 2023-03-15 17:22:36 +08:00
midoks 6b115261be up 2023-03-15 17:19:15 +08:00
midoks 059ce6228b Update receive_faq.py 2023-03-15 15:09:03 +08:00
midoks cfa396b4bb 更新 2023-03-14 20:03:53 +08:00
midoks 11e4b377ed up 2023-03-14 15:21:33 +08:00
midoks 31fe2aab92 Update receive_faq.py 2023-03-14 13:36:00 +08:00
midoks 19042a9088 Update receive_faq.py 2023-03-14 11:48:54 +08:00
midoks 2eb4543c3b Update receive_faq.py 2023-03-14 01:54:58 +08:00
midoks e33ccbfc7d Update tgbot.py 2023-03-14 01:54:08 +08:00
midoks ed8c9eed0a Update receive_faq.py 2023-03-14 01:50:56 +08:00
midoks 7163a7bbcf Update receive_faq.py 2023-03-14 01:46:19 +08:00
midoks 3f1c23ec8b Update receive_faq.py 2023-03-14 01:32:52 +08:00
midoks 3a6cb0ae2a Update receive_faq.py 2023-03-14 01:15:14 +08:00
midoks 936492d410 up 2023-03-14 01:10:04 +08:00
midoks 39d265aae7 Update tgbot.py 2023-03-14 00:15:27 +08:00
midoks 5a33098dd3 Update tgbot.py 2023-03-14 00:09:52 +08:00
midoks c9927c3fb9 tgbot加入扩展机制 2023-03-14 00:09:30 +08:00
midoks da90386816 Update tool_migrate.py 2023-03-13 11:29:00 +08:00
midoks 6be4c5977b up 2023-03-13 02:33:29 +08:00
midoks bbf93bfd9e up 2023-03-13 02:33:22 +08:00
midoks a2570af5f7 Update webstats_common.lua 2023-03-13 01:33:07 +08:00
midoks 77120cf31b up 2023-03-12 12:13:43 +08:00
midoks 395f449b93 Update webstats_common.lua 2023-03-12 12:09:53 +08:00
midoks 8be5f4aa7b Update info.json 2023-03-11 22:54:23 +08:00
midoks 3ccebf4f47 Update index.py 2023-03-11 22:48:42 +08:00
midoks 15d48accad Update tgbot.py 2023-03-11 22:43:15 +08:00
midoks d0045d831c Update tgbot.py 2023-03-11 22:42:39 +08:00
midoks a7cac3d671 up 2023-03-11 20:47:31 +08:00
midoks 7bc7fdecae Update webstats_common.lua 2023-03-11 16:40:45 +08:00
midoks 480663e2ad Update tools.py 2023-03-11 15:41:15 +08:00
midoks 2290efd060 Update config_api.py 2023-03-11 15:36:11 +08:00
midoks dece5a0532 Update config_api.py 2023-03-11 15:30:16 +08:00
midoks b0a44d24d4 Update config_api.py 2023-03-11 15:28:13 +08:00
midoks d092d9f5f2 up 2023-03-11 15:24:40 +08:00
midoks 944b3e779c Update config_api.py 2023-03-11 15:21:43 +08:00
midoks 55dc2715e9 Update config_api.py 2023-03-11 15:20:13 +08:00
midoks 84bf3abd5d Update config_api.py 2023-03-11 15:15:49 +08:00
midoks 00c9157f9b up 2023-03-11 15:15:27 +08:00
midoks faa95b0d88 Update config_api.py 2023-03-11 15:07:06 +08:00
midoks 52d0b3c940 Update config_api.py 2023-03-11 15:04:20 +08:00
midoks 0141028d41 Update config_api.py 2023-03-11 15:02:15 +08:00
midoks 9e6bf08a72 Update config_api.py 2023-03-11 15:01:46 +08:00
midoks 49ff9750cb Update config_api.py 2023-03-11 14:58:18 +08:00
midoks 75b2b4dbc2 Update config_api.py 2023-03-11 14:56:43 +08:00
midoks 667c60dda0 Update config.js 2023-03-11 14:55:48 +08:00
midoks aa6818f953 Update config_api.py 2023-03-11 14:52:58 +08:00
midoks 6f884fe60a panel ssl https 功能添加 2023-03-11 14:48:38 +08:00
midoks a56d53c672 Update config_api.py 2023-03-11 14:29:28 +08:00
midoks 00b1788172 up 2023-03-11 14:26:22 +08:00
midoks cee268fcbc Update config_api.py 2023-03-11 13:56:20 +08:00
midoks 40dd929823 Update config_api.py 2023-03-11 13:47:16 +08:00
midoks b59949e181 Update config_api.py 2023-03-11 13:41:36 +08:00
midoks 9c5975253a Update cert_api.py 2023-03-11 13:23:30 +08:00
midoks 62003b987a Update discuzx.conf 2023-03-10 14:12:27 +08:00
midoks df0a454c3a up 2023-03-10 14:09:40 +08:00
midoks 02048c3265 Update webstats_common.lua 2023-03-10 13:19:58 +08:00
midoks 65649d171d Update tgbot.py 2023-03-09 19:11:51 +08:00
midoks a136da6ec2 Update tgbot.py 2023-03-09 17:23:28 +08:00
midoks 3b25ca7e60 Update tgbot.py 2023-03-09 16:28:11 +08:00
midoks c5cf8f8afb Update info.json 2023-03-09 15:40:54 +08:00
midoks 89f7d464ab Update info.json 2023-03-09 15:28:00 +08:00
midoks 4cac6d1921 Update info.json 2023-03-09 15:25:37 +08:00
midoks dca5c82d2f Update webstats_common.lua 2023-03-09 14:56:43 +08:00
midoks 08988130b5 Update config_api.py 2023-03-09 03:00:30 +08:00
Mr Chen 8849001384 Merge pull request #392 from midoks/dev
升级图表echarts
2023-03-09 02:49:57 +08:00
midoks ae0a6b5079 升级图表echarts 2023-03-09 02:44:57 +08:00
Mr Chen d6c6ae5561 Merge pull request #391 from midoks/dev
0.13.2
2023-03-09 01:49:10 +08:00
midoks a6dc15f22d 0.13.2
* supervisor添加重启功能。
* 加入滚动写入日志 mw.writeFileLog方法。
* mysql导出优化优化。
* 添加tgbot插件[仅测试]。
* TelegramBot机器人通知-加入配置。
* mariadb更新版本。
* 在线文件编辑优化。
2023-03-09 01:47:35 +08:00
midoks 360b962bd2 Update mw.py 2023-03-09 01:42:55 +08:00
midoks 37d37e0f1d Update task.py 2023-03-09 01:32:05 +08:00
midoks ddc6da9172 Update mw.py 2023-03-09 01:30:19 +08:00
midoks ceba7ab673 up 2023-03-09 01:26:39 +08:00
midoks 384704b8e5 Update mw.py 2023-03-09 01:10:04 +08:00
midoks 232d0c2f74 Update mw.py 2023-03-09 01:01:00 +08:00
midoks ef8e6f07f5 Update mw.py 2023-03-09 00:43:34 +08:00
midoks 435e565559 Update mw.py 2023-03-09 00:42:15 +08:00
midoks ec9d7e337d Update mw.py 2023-03-09 00:36:46 +08:00
midoks b5c7a2a778 Update task.py 2023-03-09 00:32:23 +08:00
midoks 72d9c9b761 Update task.py 2023-03-09 00:28:59 +08:00
midoks 30812e1fba Update task.py 2023-03-09 00:08:49 +08:00
midoks c95cb07e8d Update task.py 2023-03-09 00:05:45 +08:00
midoks f3f2ea8ef0 通知限制频率 2023-03-08 19:40:23 +08:00
midoks 9e5a5192cb Update mw.py 2023-03-08 18:02:30 +08:00
midoks 271b3d448c Update mw.py 2023-03-08 18:01:06 +08:00
midoks b7424e7195 Update config_api.py 2023-03-08 17:57:23 +08:00
midoks b607527e1f Update config_api.py 2023-03-08 17:56:18 +08:00
midoks 3c42a4e450 对通知配置进行加密处理 2023-03-08 17:56:07 +08:00
midoks b11fd9508a Update .gitignore 2023-03-08 17:29:42 +08:00
midoks dc0504cf24 Delete notify.json 2023-03-08 17:25:12 +08:00
midoks 1d8b82395f Update public.js 2023-03-08 16:25:30 +08:00
midoks 39ac55760e Update config_api.py 2023-03-08 16:20:02 +08:00
midoks ef6071956d 在线文件编辑优化 2023-03-08 16:14:28 +08:00
midoks bbbe1c84ce Update mw.py 2023-03-07 19:24:03 +08:00
midoks 064252daad Update config.html 2023-03-07 19:20:07 +08:00
midoks 3cb63c6265 Update index.html 2023-03-07 16:28:48 +08:00
midoks b541abad42 Update index.py 2023-03-07 13:44:28 +08:00
midoks 547027be0d Update install.sh 2023-03-06 23:40:56 +08:00
midoks d786b2524a up 2023-03-06 23:21:55 +08:00
midoks abac345628 Update info.json 2023-03-06 23:10:12 +08:00
midoks d4290cbdd2 mariadb更新版本 2023-03-06 22:29:20 +08:00
midoks cfd2d99e24 Update mw.py 2023-03-06 21:31:24 +08:00
midoks 28437ccfb0 Update mw.py 2023-03-06 21:30:18 +08:00
midoks 43bf755609 Update mw.py 2023-03-06 20:35:06 +08:00
midoks de225fc8b9 0.13.1.2 2023-03-06 20:28:29 +08:00
midoks 44f891f7a3 Update mw.py 2023-03-06 20:12:52 +08:00
midoks 64d1387b03 Telegram Bot机器人通知 加入配置 2023-03-06 19:32:36 +08:00
midoks 51ccbefb04 up 2023-03-06 17:15:41 +08:00
midoks 29e3017e51 up 2023-03-06 16:49:42 +08:00
midoks 197e2d80c6 Update tgbot.py 2023-03-06 16:42:29 +08:00
midoks b8f04043bc Update tgbot.service.tpl 2023-03-06 16:41:25 +08:00
midoks 2ed70b4b96 Update tgbot.py 2023-03-06 16:39:27 +08:00
midoks d056c37be5 Update index.py 2023-03-06 16:33:18 +08:00
midoks e75abae4b9 Update tgbot.service.tpl 2023-03-06 16:32:05 +08:00
midoks 3e695770d7 Update config_api.py 2023-03-06 16:26:49 +08:00
midoks 7301edbc5a 添加tgbot插件
现在只是为了获取chat_id
2023-03-06 16:19:13 +08:00
Mr Chen 704b256408 Merge pull request #390 from midoks/dev
网站统计优化
2023-03-05 18:36:57 +08:00
midoks e129051a06 Update webstats_common.lua 2023-03-05 18:34:35 +08:00
Mr Chen d38e9f7ad0 Merge pull request #389 from midoks/dev
OP防火墙优化
2023-03-05 18:07:54 +08:00
midoks c696742866 Update init.lua 2023-03-05 18:03:41 +08:00
midoks 046389df99 Update init.lua 2023-03-05 17:37:01 +08:00
midoks 3e244ed227 导出优化 2023-03-05 14:04:16 +08:00
midoks 5016aedb0f Update index.py 2023-03-05 02:08:04 +08:00
midoks c1cd45a5f3 Update my8.0.cnf 2023-03-05 00:00:59 +08:00
midoks 79c9865a5d Update index.py 2023-03-04 23:53:54 +08:00
midoks 4082f29424 加入滚动写入日志 2023-03-04 23:07:23 +08:00
midoks d777a29d8c Update update.sh 2023-03-04 21:47:12 +08:00
Mr Chen 04e43e051e Merge pull request #388 from midoks/dev
局部优化
2023-03-02 16:57:17 +08:00
midoks dffe9a77e7 Update layout.html 2023-03-02 00:57:02 +08:00
midoks 1b1462586e Update orm.py 2023-03-02 00:49:44 +08:00
midoks f11d2db761 添加重启功能 2023-03-01 18:41:32 +08:00
midoks 842c16540a Update index.py 2023-03-01 18:03:14 +08:00
midoks 614cc1032f Update webstats_log.lua 2023-03-01 14:03:46 +08:00
midoks ad46b2050e Update config.json 2023-03-01 01:40:57 +08:00
midoks 8109989927 Update layout.html 2023-02-28 19:41:13 +08:00
Mr Chen 9d9b39dfe2 Merge pull request #387 from midoks/dev
0.13.1
2023-02-28 19:11:06 +08:00
midoks 422514c40a 0.13.1
* 关闭issue,建立bbs.midoks.me。问题集中处理,发挥群众的力量。
* 添加站操作回调钩子site_cb。 网站统计和OP防火墙不再手动重载配置
* 修复ubuntu20 pureftp 安装时,端口没有加入安全里
* 增加global_static hook关键字,并优化menu的文件加载hook
* 各种细节优化。
2023-02-28 19:09:54 +08:00
midoks 632568643b Update site_api.py 2023-02-28 17:08:26 +08:00
midoks a5f29a2a6a Update cert_api.py 2023-02-28 16:26:31 +08:00
midoks b02705aa5a up 2023-02-28 03:00:46 +08:00
midoks 1f9ab560e3 Update files.js 2023-02-28 02:18:39 +08:00
midoks b3970326cd Update index.py 2023-02-28 01:57:19 +08:00
midoks f6d008e0b6 Update index.py 2023-02-28 01:50:54 +08:00
midoks 6f9a49ad7a up 2023-02-28 01:48:51 +08:00
midoks fc3c7d334a Update public.js 2023-02-28 00:17:39 +08:00
midoks 1030d1b923 site_cb 添加站操作回调钩子。 网站统计和OP防火墙不再手动重载配置 2023-02-28 00:02:16 +08:00
midoks 94d4a90bcc Update webstats_common.lua 2023-02-27 19:35:52 +08:00
midoks da4b872666 Update README.md 2023-02-27 17:57:17 +08:00
midoks cf15b19f4b Update install.sh 2023-02-26 21:46:25 +08:00
midoks aa9cdaada4 Update commit.tpl 2023-02-26 03:16:45 +08:00
midoks 659c9fe16b 修复ubuntu 20 pureftp 安装时,端口没有加入安全里 2023-02-26 02:20:06 +08:00
midoks 2b8c6d6e43 Update firewall_api.py 2023-02-26 01:39:52 +08:00
midoks 263f83088f Update firewall_api.py 2023-02-26 01:38:55 +08:00
midoks 374c938ac0 Update firewall_api.py 2023-02-26 01:38:32 +08:00
midoks 6aa73b0cae Update firewall_api.py 2023-02-26 01:36:45 +08:00
midoks 7f731ae06f Update README.md 2023-02-26 01:12:08 +08:00
midoks f87aff704c Update rhel.sh 2023-02-25 23:36:14 +08:00
midoks be9fa87133 Update rhel.sh 2023-02-25 23:31:36 +08:00
midoks de6fc19dee Create discuz.conf 2023-02-25 21:33:50 +08:00
midoks 3987c6d3dc Update config_api.py 2023-02-25 08:37:26 +08:00
midoks 96875052cd Update index.py 2023-02-25 08:25:05 +08:00
midoks 583de57f96 Update plugins_api.py 2023-02-25 08:21:20 +08:00
midoks 41b7245f03 Update plugins_api.py 2023-02-25 08:15:38 +08:00
midoks ee3684706f Update info.json 2023-02-25 07:48:32 +08:00
midoks 07936dfb81 update 2023-02-25 07:35:46 +08:00
midoks 5c46202be0 增加global_static hook关键字,并优化menu的文件加载hook
"hook":[
		{
			"tag":"global_static",
			"global_static": {
				"css_path":"menu/own_style.css",
				"js_path":"js/own_style.js"
			}
		}
	],
2023-02-25 07:26:48 +08:00
midoks 7123a15457 Update install.sh 2023-02-24 18:08:46 +08:00
midoks 4aeb45b1d5 Update install.sh 2023-02-24 17:55:13 +08:00
midoks 006a62be22 Update lib.sh 2023-02-24 17:25:04 +08:00
midoks 1e91d11125 Update mw.tpl 2023-02-24 17:22:22 +08:00
midoks 99fb4aa723 up 2023-02-24 17:14:28 +08:00
midoks 5c5bbb2da2 up 2023-02-24 17:12:31 +08:00
midoks 8b05045901 Update install.sh 2023-02-24 17:07:24 +08:00
midoks 1b73439525 Update install_dev.sh 2023-02-24 17:00:10 +08:00
midoks ec51ad016a Update install_dev.sh 2023-02-24 16:57:24 +08:00
midoks a42fae66ac Update install_dev.sh 2023-02-24 16:53:48 +08:00
midoks b4c635c2e5 Update install_dev.sh 2023-02-24 16:49:03 +08:00
midoks 9802bc5915 Update pure-ftpd.conf 2023-02-24 13:29:16 +08:00
Mr Chen 196fbbdd7d Merge pull request #382 from midoks/dev
0.13.0
2023-02-24 05:59:59 +08:00
midoks fa278abd50 Update index.py 2023-02-24 05:53:33 +08:00
midoks f9b2dbcb5e Update index.py 2023-02-24 05:46:39 +08:00
midoks a8808be9ae Update index.py 2023-02-24 05:41:50 +08:00
midoks 4122de13e3 Update index.py 2023-02-24 05:39:52 +08:00
midoks 4acae8e5f5 up 2023-02-24 05:38:59 +08:00
midoks 1abb611c3e 版本更新 0.13.0 2023-02-24 05:17:44 +08:00
midoks 726f9fa0d2 #374 2023-02-24 04:15:23 +08:00
midoks cfb64caadc Update site_api.py 2023-02-24 04:09:50 +08:00
midoks f501dd5150 Update site_api.py 2023-02-24 04:07:19 +08:00
midoks d1fe006e39 Update site_api.py 2023-02-24 03:28:48 +08:00
midoks d4db5dbfac up 2023-02-24 03:28:18 +08:00
midoks efa512a3f6 #374 2023-02-24 03:16:52 +08:00
midoks b53436343d up 2023-02-24 02:40:09 +08:00
midoks bb1a634f3c Update site_api.py 2023-02-24 02:29:14 +08:00
midoks acda55cc55 Update index.py 2023-02-24 01:40:02 +08:00
midoks 0ff0728517 Update index.py 2023-02-24 01:30:17 +08:00
midoks c575f55354 Update app.js 2023-02-24 01:05:32 +08:00
midoks d58339dbcb Update index.py 2023-02-24 00:07:19 +08:00
midoks f6a18fa25f Update index.py 2023-02-24 00:03:48 +08:00
midoks 3016eff372 Update app.js 2023-02-23 17:29:38 +08:00
midoks ca518591f3 up 2023-02-23 17:27:15 +08:00
midoks d2c74f2243 up 2023-02-23 17:17:46 +08:00
midoks 71dbf8e359 Update app.js 2023-02-23 15:39:16 +08:00
midoks cb2ad0ca82 up 2023-02-23 15:18:44 +08:00
midoks a157db7879 Update index.py 2023-02-23 03:32:30 +08:00
midoks fb949f4ee6 up 2023-02-23 01:25:00 +08:00
midoks b91ae3fde2 Update index.py 2023-02-22 23:46:28 +08:00
midoks b508e8003b Update index.py 2023-02-22 23:13:44 +08:00
midoks 0632a4b535 Update index.py 2023-02-22 23:13:17 +08:00
midoks 397e0b89a5 Update index.py 2023-02-22 22:59:45 +08:00
midoks 2427bf81cd Update index.py 2023-02-22 22:44:16 +08:00
midoks 4179bbf580 Update index.py 2023-02-22 22:40:29 +08:00
midoks b93c3bb88e Update index.py 2023-02-22 22:37:19 +08:00
midoks a52c854afd Update index.py 2023-02-22 22:36:10 +08:00
midoks d7e5cf1f45 Update index.py 2023-02-22 21:55:49 +08:00
midoks cfb444deac Update files_api.py 2023-02-22 20:54:54 +08:00
midoks 78615451ac up 2023-02-22 20:52:12 +08:00
midoks 0134643c83 Update db.py 2023-02-22 18:18:40 +08:00
midoks 70ddd1c86f Update index.py 2023-02-22 17:55:17 +08:00
midoks 808dc743ef Update files_api.py 2023-02-22 14:59:40 +08:00
midoks e30693f9f2 Update files_api.py 2023-02-22 14:28:01 +08:00
midoks 5c97fbe011 Update __init__.py 2023-02-22 14:27:48 +08:00
midoks 6419a18525 up 2023-02-21 21:10:34 +08:00
midoks 4a804e9243 Update index.py 2023-02-19 18:12:08 +08:00
midoks d44526004f up 2023-02-19 18:02:26 +08:00
midoks c1f402b278 up 2023-02-19 00:10:06 +08:00
midoks 45a3eec1b5 Update install_dev.sh 2023-02-18 23:09:51 +08:00
midoks d6f41ceb6a Update install_dev.sh 2023-02-18 23:06:53 +08:00
midoks a1bc0f6faf Update install_dev.sh 2023-02-18 22:58:21 +08:00
midoks 8420961cf7 Update install_dev.sh 2023-02-18 22:54:58 +08:00
midoks 421594c01d Update install_dev.sh 2023-02-18 22:48:30 +08:00
midoks ca13e8ad77 Update install_dev.sh 2023-02-18 22:46:05 +08:00
midoks f161f24253 up 2023-02-18 22:44:42 +08:00
midoks e5ab03951f Update README.md 2023-02-18 22:08:13 +08:00
midoks 5b45bab36d Update install_dev.sh 2023-02-18 22:06:51 +08:00
midoks 0594d3f9ce Update README.md 2023-02-18 22:04:11 +08:00
midoks ad541216c5 up 2023-02-18 16:59:33 +08:00
midoks 1adc0c1405 Update rhel.sh 2023-02-18 15:35:16 +08:00
midoks b22185b374 Update rhel.sh 2023-02-18 14:09:02 +08:00
midoks 02f3107e93 Update app.js 2023-02-18 02:04:52 +08:00
midoks 52fece867d up 2023-02-18 01:49:20 +08:00
midoks 2e3578dcf1 up 2023-02-18 01:39:26 +08:00
midoks 73b09a7886 up 2023-02-17 22:39:49 +08:00
midoks f33c7e5a5e up 2023-02-17 19:57:03 +08:00
midoks 3e90db2c8d Update system_api.py 2023-02-17 19:54:44 +08:00
midoks d599363609 Update index.py 2023-02-17 16:30:32 +08:00
midoks ec3167f239 Update __init__.py 2023-02-17 16:30:25 +08:00
midoks 2b1099b6e9 Update __init__.py 2023-02-17 15:42:28 +08:00
midoks e55a0760e3 Update mw.tpl 2023-02-17 15:22:15 +08:00
midoks 5c1353a38f Update mw.tpl 2023-02-17 15:20:52 +08:00
midoks f95684b316 Update mw.tpl 2023-02-17 15:20:39 +08:00
midoks 6fc729ccf9 Update __init__.py 2023-02-17 15:17:41 +08:00
midoks 45d0c4fc4a Update __init__.py 2023-02-17 15:16:11 +08:00
midoks 6759b9055c ip 2023-02-17 15:01:26 +08:00
midoks de694b2465 up 2023-02-17 14:56:44 +08:00
midoks c7b3daca36 up 2023-02-16 17:02:33 +08:00
midoks 452769233f up 2023-02-16 17:00:09 +08:00
midoks 8d196a3aa1 Update index.py 2023-02-16 16:26:22 +08:00
midoks 01baf509ad up 2023-02-16 15:49:55 +08:00
midoks d59ee2c843 Update install.sh 2023-02-16 15:39:08 +08:00
midoks 8919d5734e Update index.py 2023-02-16 14:15:15 +08:00
midoks bb91b30d6d Update index.py 2023-02-16 14:06:41 +08:00
midoks 103ab2e099 Update index.py 2023-02-15 22:45:44 +08:00
midoks 0d33d0db79 Update install.sh 2023-02-15 22:35:29 +08:00
midoks 6d9f4cfa08 Update tools.py 2023-02-15 22:31:22 +08:00
midoks c88c95ba21 Update macos.sh 2023-02-15 22:26:53 +08:00
midoks a705f6a8e4 Update install.sh 2023-02-15 22:24:51 +08:00
midoks 3f40ed0a01 up 2023-02-15 22:24:46 +08:00
midoks 39653896bf Update install_dev.sh 2023-02-15 22:15:08 +08:00
midoks 31d665d962 Update install.sh 2023-02-15 22:05:16 +08:00
midoks 811fa4a40d Update install_dev.sh 2023-02-15 22:04:58 +08:00
midoks 320f58424d Update README.md 2023-02-15 21:56:19 +08:00
midoks 376f0f0a4e up 2023-02-15 21:55:21 +08:00
midoks 0efb700cee Update README.md 2023-02-15 15:54:14 +08:00
midoks ff3fcae366 Update config_api.py 2023-02-15 15:50:55 +08:00
Mr Chen 22d94ce67c Merge pull request #371 from midoks/dev
安装脚本优化3
2023-02-14 22:24:04 +08:00
midoks 042fd7ac6d Update ubuntu.sh 2023-02-14 22:23:04 +08:00
midoks 1a48f52dad up 2023-02-14 22:22:06 +08:00
Mr Chen fc5970c65d Merge pull request #370 from midoks/dev
安装脚本优化2
2023-02-14 22:09:05 +08:00
midoks e758698ee2 Update debian.sh 2023-02-14 22:02:28 +08:00
Mr Chen ea03bb056a Merge pull request #369 from midoks/dev
安装脚本优化
2023-02-14 21:59:22 +08:00
midoks 088346fd5e 安装脚本优化 2023-02-14 21:58:30 +08:00
midoks cbcb686363 Update firewall_api.py 2023-02-14 21:07:22 +08:00
Mr Chen 628175a8ee Merge pull request #368 from midoks/dev
0.12.3
2023-02-14 20:13:04 +08:00
Mr Chen 96d0115257 Merge branch 'master' into dev 2023-02-14 20:12:50 +08:00
midoks 801fdf51a7 0.12.3
### 版本更新 0.12.3

* 优先使用firewalld防火墙。
* PHP[APT]加入curl扩展。
* 配置添加【未认证响应状态】功能。
* 存在ipv6时,启动时强制开启。
* OP防火墙-性能优化。
* 网站统计优化。
* 优化backup_ftp插件。
* 各种细节优化。
2023-02-14 20:11:16 +08:00
midoks 24fa3a7ca9 优化backup_ftp插件 2023-02-14 18:29:08 +08:00
midoks 3dc781498c Update index.py 2023-02-14 18:24:43 +08:00
midoks c3afaeb35a Update index.py 2023-02-14 18:23:42 +08:00
midoks 4390180a89 Update config_api.py 2023-02-14 18:20:54 +08:00
midoks 98e22f6eeb Update index.py 2023-02-14 18:19:00 +08:00
midoks 3bfd0f34f5 Update index.py 2023-02-14 18:14:27 +08:00
midoks ec8e46494a Update crontab.js 2023-02-14 18:10:14 +08:00
midoks 7cb9b0acec Update index.py 2023-02-14 17:56:16 +08:00
midoks f97d2a5987 Update ngx_debug.sh 2023-02-13 20:46:19 +08:00
midoks 5a50fe70a8 Update ngx_debug.sh 2023-02-13 20:45:57 +08:00
midoks 4ecb28575e Update install.sh 2023-02-13 20:34:25 +08:00
midoks 07bf8f162c Update debian.sh 2023-02-13 19:27:08 +08:00
midoks 19beb1bccc Update requirements.txt 2023-02-13 19:21:24 +08:00
midoks 33c27d7924 up 2023-02-13 18:56:49 +08:00
midoks a9fb6c9ec9 up 2023-02-13 18:15:10 +08:00
midoks 7198a4de95 up 2023-02-13 15:56:41 +08:00
midoks 53cb56ddf2 up 2023-02-13 15:39:57 +08:00
midoks e4582f328c Update index.py 2023-02-13 14:35:14 +08:00
midoks bb7f1b6a7d up 2023-02-13 14:16:06 +08:00
midoks 1781d879d1 up 2023-02-13 13:36:32 +08:00
midoks d89158124f Update ngx_debug.sh 2023-02-13 03:29:54 +08:00
midoks bfdad5f9a3 Update ngx_debug.sh 2023-02-13 03:23:40 +08:00
midoks 165d9ba14d Update webstats_common.lua 2023-02-13 03:05:26 +08:00
midoks ad102aa940 Update ngx_debug.sh 2023-02-13 03:01:16 +08:00
midoks 1489d15d74 Update ngx_debug.sh 2023-02-13 02:31:08 +08:00
midoks 2dbda3e6dd 优化,Linux系统不再加入到计划任务获取cpu使用率 2023-02-13 01:58:36 +08:00
midoks 4775d4f756 Update waf_common.lua 2023-02-13 01:45:49 +08:00
midoks f57fd600e6 Update test_get_cpu.lua 2023-02-13 01:38:24 +08:00
midoks bf281107b2 up 2023-02-13 00:26:31 +08:00
midoks 083fe59fa5 up 2023-02-12 17:29:29 +08:00
midoks 8f36e0ccb2 Update centos.sh 2023-02-12 02:15:12 +08:00
midoks a5b3a650eb up 2023-02-12 02:14:18 +08:00
midoks 177a08af91 Update waf_common.lua 2023-02-12 02:12:34 +08:00
midoks 5ef4b3d05d firewalld优先 2023-02-12 02:12:28 +08:00
midoks ad3d93cf8b firewalld防火墙优先 2023-02-12 02:03:57 +08:00
midoks 72643b7776 Update rhel.sh 2023-02-12 02:02:27 +08:00
midoks 45128636b0 up 2023-02-12 01:17:23 +08:00
midoks 7b962335e4 up 2023-02-12 01:08:03 +08:00
midoks c0c67095be up 2023-02-12 01:02:19 +08:00
midoks b3a0f11a80 up 2023-02-12 00:44:35 +08:00
midoks 088337765c Update webstats_worker.lua 2023-02-12 00:35:52 +08:00
midoks 066e7087c9 Update webstats_common.lua 2023-02-12 00:35:39 +08:00
midoks 29144595a6 网站统计 2023-02-12 00:22:39 +08:00
midoks 45c2b3cdca Update index.py 2023-02-11 23:44:19 +08:00
midoks e3ecdfb2b3 Update index.py 2023-02-11 23:43:51 +08:00
midoks 560d482f31 up 2023-02-11 23:25:29 +08:00
midoks 62ffc94b69 up 2023-02-11 22:34:18 +08:00
midoks 0cb10cc926 Update webstats_common.lua 2023-02-11 22:23:34 +08:00
midoks fb4eb8747c Update webstats_common.lua 2023-02-11 22:16:08 +08:00
midoks 1a26b83a46 Update webstats_log.lua 2023-02-11 22:06:04 +08:00
midoks 7c2316f005 Update webstats_common.lua 2023-02-11 21:50:32 +08:00
midoks 149baeb1fc Update webstats_log.lua 2023-02-11 21:42:57 +08:00
midoks 9714bcb419 Update init.lua 2023-02-11 17:45:17 +08:00
midoks 4e6a54dbad Update index.py 2023-02-11 17:18:24 +08:00
midoks 18498813c6 up 2023-02-11 17:06:24 +08:00
midoks 854e34a90c Update mw.py 2023-02-11 16:48:57 +08:00
midoks a0898c849e Update lua.conf 2023-02-11 16:47:46 +08:00
midoks 3a26b71828 ip 2023-02-11 16:45:28 +08:00
midoks f500dcac8b Update init_worker.lua 2023-02-11 16:06:25 +08:00
midoks 3a6e2e6e4b Update cpu_usage_file.sh 2023-02-11 16:06:08 +08:00
midoks 1d439e788c Update soft.html 2023-02-11 15:25:44 +08:00
midoks 75a2fcdaaf Update debian.sh 2023-02-11 15:24:17 +08:00
midoks 2ca8598671 up 2023-02-11 06:04:55 +08:00
midoks 2d42486ac5 Update index.py 2023-02-11 05:30:38 +08:00
midoks 24f22b5b8c up 2023-02-11 05:28:54 +08:00
midoks 68f8638638 up 2023-02-11 05:28:27 +08:00
midoks fe6b16eda4 Update index.py 2023-02-11 05:27:34 +08:00
midoks 4e35c34854 up 2023-02-11 05:24:53 +08:00
midoks cc51d9501f Update init.lua 2023-02-11 05:04:37 +08:00
midoks c08cfd4763 Update ip_white.json 2023-02-11 05:00:58 +08:00
midoks 5fdcb8bf71 up 2023-02-11 04:43:30 +08:00
midoks ce3b232c4b Update mw.py 2023-02-11 04:03:41 +08:00
midoks ec7ae65f7d up 2023-02-11 02:52:02 +08:00
midoks e4c5212ac4 Update public.js 2023-02-11 02:51:42 +08:00
midoks 23442accaf Update mw.py 2023-02-11 02:51:25 +08:00
midoks 2e6f5f9add up 2023-02-11 02:51:17 +08:00
midoks 110e356fae up 2023-02-09 17:05:06 +08:00
midoks a243d088ee Update tool_task.py 2023-02-05 16:22:17 +08:00
midoks 365fd466c2 更快获取cpu使用率 2023-02-05 16:21:30 +08:00
midoks d1304de69e Update cli.sh 2023-02-05 15:22:53 +08:00
midoks e51fa2608d Update cli.sh 2023-02-05 15:21:45 +08:00
midoks cbfcd00317 Update mw.tpl 2023-02-05 15:20:08 +08:00
midoks 7a96d3abc5 Update mw.tpl 2023-02-05 15:19:50 +08:00
midoks 33a510a5b5 Update mw.tpl 2023-02-05 12:50:26 +08:00
midoks e8942128b8 Update tool_task.py 2023-02-05 12:49:21 +08:00
midoks 7e2bd928e2 Update tool_task.py 2023-02-05 12:42:30 +08:00
midoks 89185476aa 优化获取cpu方式。 2023-02-05 12:37:49 +08:00
midoks f491641ab8 Create cpu_usage.sh 2023-02-05 12:25:57 +08:00
midoks 8b108d1aff Update ubuntu.sh 2023-02-05 12:16:55 +08:00
midoks 2cfa7ec2ab Update ubuntu.sh 2023-02-05 12:07:29 +08:00
midoks d63aae100d Update ubuntu.sh 2023-02-05 11:57:44 +08:00
midoks e8249adc53 Update tool_task.py 2023-02-05 03:48:22 +08:00
midoks 281427e479 Update tool_task.py 2023-02-05 03:48:03 +08:00
midoks af775fc77d OP防火墙-获取cpu优化 2023-02-05 03:40:18 +08:00
midoks f328354125 #362 2023-02-05 00:25:59 +08:00
midoks 1f70f962cf Update crontab.js 2023-02-05 00:25:25 +08:00
midoks 414787447e Update README.md 2023-02-04 19:27:55 +08:00
midoks 979f2174e5 Update README.md 2023-02-03 21:28:29 +08:00
midoks 84d1c96094 Update config_api.py 2023-02-03 21:17:25 +08:00
midoks 0d8d9022a0 Update mw.py 2023-02-03 21:17:07 +08:00
midoks 44d0e9e11c 存在ipv6,启动时强制开启 2023-02-03 13:42:35 +08:00
midoks 771d6e04ba Update mw.tpl 2023-02-03 13:39:45 +08:00
midoks 87563daa1d Update index.html 2023-02-02 20:50:42 +08:00
midoks 9fefb285e1 Update .gitignore 2023-02-02 20:47:18 +08:00
midoks b9ca4fc11e 配置添加【未认证响应状态】功能 2023-02-02 18:04:44 +08:00
midoks 2646d0565d Update debian.sh 2023-02-02 15:23:35 +08:00
midoks e1f900f1c5 Update tools.py 2023-02-02 14:59:15 +08:00
midoks 908b3341b2 Update rhel.sh 2023-02-01 13:25:01 +08:00
midoks 5aef2467b1 Update debian.sh 2023-02-01 13:20:53 +08:00
midoks f59114a688 自动获取ssh端口 2023-02-01 13:09:28 +08:00
midoks 363ed8b3ff Update index.py 2023-01-31 20:07:39 +08:00
midoks 3970feacc3 Update gitea.js 2023-01-31 19:48:30 +08:00
midoks f6c528149e Update gitea.js 2023-01-31 19:41:00 +08:00
midoks 8f6b5ddba9 Update gitea.js 2023-01-31 19:36:50 +08:00
midoks ef350b9fd2 Update gitea.js 2023-01-31 19:33:46 +08:00
midoks 004dfb5e7d apt php curl是必须的扩展 2023-01-30 14:01:57 +08:00
midoks 3c08d7c159 Update files_api.py 2023-01-30 01:17:09 +08:00
midoks e227204065 编码识别优化。 2023-01-30 00:50:10 +08:00
midoks ce653b7a6a Update README.md 2023-01-29 22:31:52 +08:00
Mr Chen a207215775 Merge pull request #355 from midoks/midoks-patch-1
Update debian.sh
2023-01-29 20:52:22 +08:00
Mr Chen 8115b0fb4d Update debian.sh 2023-01-29 20:48:51 +08:00
midoks 048bd573e8 修复API接口使用 2023-01-29 14:32:38 +08:00
midoks 918ea8d0f9 Update mw.tpl 2023-01-28 11:22:57 +08:00
midoks 97d2fd5a63 Update debian.sh 2023-01-28 10:50:31 +08:00
midoks 617a517048 Update index.html 2023-01-28 01:57:54 +08:00
midoks 2e7910a84c 一键迁移初始化 2023-01-28 01:34:48 +08:00
midoks 2ee4c4e3fd 页面更新跟随更新一遍环境 2023-01-27 21:58:10 +08:00
midoks 9ae4d32ed4 卸载时,删除首页显示 2023-01-27 21:05:16 +08:00
midoks 90a7f4ea10 Update .gitignore 2023-01-27 20:09:09 +08:00
midoks d22cb8305d Update soft.html 2023-01-27 20:08:34 +08:00
midoks a7a78f2103 Update .gitignore 2023-01-27 16:20:50 +08:00
Mr Chen db7ec00c07 Merge pull request #352 from midoks/dev
优化在命令行下修改端口命令
2023-01-27 16:09:29 +08:00
midoks dd21d25295 Update tools.py 2023-01-27 16:04:54 +08:00
midoks f7360aa081 Update tools.py 2023-01-27 16:02:21 +08:00
midoks 1d1ba7192a Update tools.py 2023-01-27 16:00:02 +08:00
midoks 0bf540c5e7 Update mw.py 2023-01-27 15:54:55 +08:00
249 changed files with 19133 additions and 1639 deletions
+16
View File
@@ -0,0 +1,16 @@
name: sync2gitee
on: [push]
jobs:
repo-sync:
runs-on: ubuntu-latest
steps:
- name: Mirror the Github organization repos to Gitee.
uses: Yikun/hub-mirror-action@master
with:
src: 'github/midoks'
dst: 'gitee/midoks'
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
static_list: "mdserver-web"
force_update: true
+10 -2
View File
@@ -151,14 +151,18 @@ data/system.db-journal
data/hook_*.json
data/letsencrypt.json
data/basic_auth.json
data/notify.json
data/api.json
data/bind_domain.pl
data/unauthorized_status.pl
plugins/vip_*
plugins/own_*
plugins/my_*
plugins/l2tp
plugins/openlitespeed
plugins/migration_api
plugins/system_safe
plugins/tamper_proof
plugins/cryptocurrency_trade
plugins/gdrive
plugins/mtproxy
plugins/zimg
@@ -171,3 +175,7 @@ plugins/file_search
debug.out
mdioks.session-journal
*.session
+35 -28
View File
@@ -29,6 +29,13 @@
基本上可以使用,后续会继续优化!欢迎提供意见!
- 吹水组 - https://t.me/mdserver_web
- 交流论坛 - https://bbs.midoks.me
```
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
Talk is cheap, show me the code. -- linus
```
- [兼容性测试报告](/compatibility.md)
- [常用命令说明](/cmd.md)
@@ -38,6 +45,7 @@
* PHP[53-82] - PHP是世界上最好的编程语言。
* MySQL - 一种关系数据库管理系统。
* MariaDB - 是MySQL的一个重要分支。
* MySQL[APT/YUM] - 一种关系数据库管理系统。
* MongoDB - 一种非关系NOSQL数据库管理系统。
* phpMyAdmin - 著名Web端MySQL管理工具。
* Memcached - 一个高性能的分布式内存对象缓存系统。
@@ -66,7 +74,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-81]支持phpMyAdmin[5.2.0]
PHP[72-82]支持phpMyAdmin[5.2.0]
```
# 特别赞助
@@ -80,49 +88,48 @@ PHP[72-81]支持phpMyAdmin[5.2.0]
| 服务商 | LOGO | 推广地址 | 优惠码 |
| ------------- |----------|-----------|-------|
| digitalvirt |[![digitalvirt](https://digitalvirt.com/templates/BlueWhite/img/logo-dark.svg)](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | mdserver-web |
| mvirtua |[![mvirtua](https://mvirtua.com/upload/logo-black.png)](https://mvirtua.com/aff/FUSKXVDH) | https://mvirtua.com/aff/FUSKXVDH | mdserver-web (全场8折)|
# Docker
- 由[DDSRem](https://github.com/DDSRem)开发维护。
- https://hub.docker.com/r/ddsderek/mw-server
- https://hub.docker.com/r/ddsderek/mw
```
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.12.2
* 开放菜单权限配置。
* 升级SSH终端2.0。
* 增加已安装类型。
* 加入切换linux软件源的命令。
* iptables安装优化。
* 网站统计POST获取数据优化。
* mysql[apt/yum]迁移优化。
* 优化防火墙导入。
* 图标可设置。
* 各种细节优化。
### 版本更新 0.15.1
* 升级功能优化。
* 域名伪静态保存优化。
* 自动同步gitee。
* nezha保存优化。
* OP防火墙优化(站点配置-状态关闭后,不再防御)-已安装的,需要重载。
* 修复子目录绑定-伪静态问题。
* [插件]docker - 添加IP地址池。
* PHP下载中国优化。
* 监控页面-自定义时间优化。
### JSDelivr安装地址
- 初始安装
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
```
- 直接更新
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
```
### 备用地址
@@ -130,20 +137,20 @@ wget -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scri
- 初始安装
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
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 -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
```
@@ -152,22 +159,22 @@ wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/maste
- 需已经安装mdserver-web
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
```
### DEV使用
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/install_dev.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/update_dev.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
```
### 捐赠地址 USDT(TRC20)
+1
View File
@@ -28,6 +28,7 @@ from route import app, socketio
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
from gevent import monkey
monkey.patch_all()
+10 -10
View File
@@ -371,8 +371,7 @@ fi
response = urllib.request.urlopen(req, timeout=timeout)
return response
except Exception as ex:
self.getError()
# self.getError()
raise Exception("requestsPost: {}".format(self.getError(str(ex))))
def getRequestJson(self, response):
@@ -931,7 +930,8 @@ fi
index).encode()
)
X509Req.set_pubkey(pk)
X509Req.set_version(2)
# X509Req.set_version(2)
X509Req.set_version(0)
X509Req.sign(pk, self.__digest)
return OpenSSL.crypto.dump_certificate_request(OpenSSL.crypto.FILETYPE_ASN1, X509Req)
@@ -1007,7 +1007,7 @@ fi
try:
result = {}
x509 = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, public.readFile(pem_file))
OpenSSL.crypto.FILETYPE_PEM, mw.readFile(pem_file))
# 取产品名称
issuer = x509.get_issuer()
result['issuer'] = ''
@@ -1281,16 +1281,16 @@ fullchain.pem 粘贴到证书输入框
# 获取当前正在使用此证书的网站目录
def getSslUsedSite(self, save_path):
pkey_file = '{}/privkey.pem'.format(save_path)
pkey = public.readFile(pkey_file)
pkey = mw.readFile(pkey_file)
if not pkey:
return False
cert_paths = 'vhost/cert'
import panelSite
args = public.dict_obj()
args = mw.dict_obj()
args.siteName = ''
for c_name in os.listdir(cert_paths):
skey_file = '{}/{}/privkey.pem'.format(cert_paths, c_name)
skey = public.readFile(skey_file)
skey = mw.readFile(skey_file)
if not skey:
continue
if skey == pkey:
@@ -1298,7 +1298,7 @@ fullchain.pem 粘贴到证书输入框
run_path = panelSite.panelSite().GetRunPath(args)
if not run_path:
continue
sitePath = public.M('sites').where(
sitePath = mw.M('sites').where(
'name=?', c_name).getField('path')
if not sitePath:
continue
@@ -1316,7 +1316,7 @@ fullchain.pem 粘贴到证书输入框
self.__config['orders'] = {}
import panelSite
siteObj = panelSite.panelSite()
args = public.dict_obj()
args = mw.dict_obj()
for siteName in os.listdir(cert_path):
try:
cert_file = '{}/{}/fullchain.pem'.format(cert_path, siteName)
@@ -1522,7 +1522,7 @@ fullchain.pem 粘贴到证书输入框
self.__config['orders'][i]['auth_to'] = auth_to
# 是否到了允许重试的时间
if 'next_retry_time' in self._config['orders'][i]:
if 'next_retry_time' in self.__config['orders'][i]:
timeout = self.__config['orders'][i][
'next_retry_time'] - int(time.time())
if timeout > 0:
+8 -7
View File
@@ -840,7 +840,8 @@ class cert_request:
index).encode()
)
X509Req.set_pubkey(pk)
X509Req.set_version(2)
# X509Req.set_version(2)
X509Req.set_version(0)
X509Req.sign(pk, self.__digest)
return OpenSSL.crypto.dump_certificate_request(OpenSSL.crypto.FILETYPE_ASN1, X509Req)
@@ -916,7 +917,7 @@ class cert_request:
try:
result = {}
x509 = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, public.readFile(pem_file))
OpenSSL.crypto.FILETYPE_PEM, mw.readFile(pem_file))
# 取产品名称
issuer = x509.get_issuer()
result['issuer'] = ''
@@ -1186,16 +1187,16 @@ fullchain.pem 粘贴到证书输入框
# 获取当前正在使用此证书的网站目录
def getSslUsedSite(self, save_path):
pkey_file = '{}/privkey.pem'.format(save_path)
pkey = public.readFile(pkey_file)
pkey = mw.readFile(pkey_file)
if not pkey:
return False
cert_paths = 'vhost/cert'
import panelSite
args = public.dict_obj()
args = mw.dict_obj()
args.siteName = ''
for c_name in os.listdir(cert_paths):
skey_file = '{}/{}/privkey.pem'.format(cert_paths, c_name)
skey = public.readFile(skey_file)
skey = mw.readFile(skey_file)
if not skey:
continue
if skey == pkey:
@@ -1203,7 +1204,7 @@ fullchain.pem 粘贴到证书输入框
run_path = panelSite.panelSite().GetRunPath(args)
if not run_path:
continue
sitePath = public.M('sites').where(
sitePath = mw.M('sites').where(
'name=?', c_name).getField('path')
if not sitePath:
continue
@@ -1221,7 +1222,7 @@ fullchain.pem 粘贴到证书输入框
self.__config['orders'] = {}
import panelSite
siteObj = panelSite.panelSite()
args = public.dict_obj()
args = mw.dict_obj()
for siteName in os.listdir(cert_path):
try:
cert_file = '{}/{}/fullchain.pem'.format(cert_path, siteName)
+234 -14
View File
@@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.12.2'
__version = '0.15.1'
__api_addr = 'data/api.json'
def __init__(self):
@@ -348,7 +348,23 @@ class config_api:
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
if not os.path.exists(certPath):
mw.createSSL()
# 不再自动生成证书
# mw.createSSL()
cert['privateKey'] = ''
cert['is_https'] = ''
cert['certPem'] = ''
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = {'endtime': 0, 'subject': '无',
'notAfter': '无', 'notBefore': '无', 'issuer': '无'}
return cert
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
cert['is_https'] = ''
else:
ssl_data = mw.readFile(panel_ssl)
if ssl_data.find('$server_port !~ 443') != -1:
cert['is_https'] = 'checked'
cert['privateKey'] = mw.readFile(keyPath)
cert['certPem'] = mw.readFile(certPath)
@@ -380,13 +396,86 @@ class config_api:
mw.writeFile('ssl/input.pl', 'True')
return mw.returnJson(True, '证书已保存!')
# 设置面板SSL证书设置
def setPanelHttpToHttpsApi(self):
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
keyPath = 'ssl/private.pem'
if not os.path.exists(keyPath):
return mw.returnJson(False, '未申请SSL证书!')
is_https = request.form.get('https', '').strip()
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
return mw.returnJson(False, '未开启面板SSL!')
if is_https == 'false':
conf = mw.readFile(panel_ssl)
if conf:
if conf.find('ssl_certificate') == -1:
return mw.returnJson(False, '当前未开启SSL')
to = "#error_page 404/404.html;\n\
#HTTP_TO_HTTPS_START\n\
if ($server_port !~ 443){\n\
rewrite ^(/.*)$ https://$host$1 permanent;\n\
}\n\
#HTTP_TO_HTTPS_END"
conf = conf.replace('#error_page 404/404.html;', to)
mw.writeFile(panel_ssl, conf)
else:
conf = mw.readFile(panel_ssl)
if conf:
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*}"
conf = re.sub(rep, '', conf)
mw.writeFile(panel_ssl, conf)
mw.restartWeb()
action = '开启'
if is_https == 'true':
action = '关闭'
return mw.returnJson(True, action + 'HTTPS跳转成功!')
# 删除面板证书
def delPanelSslApi(self):
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
siteName = mw.readFile(bind_domain).strip()
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
if os.path.exists(src_letpath) or os.path.exists(dst_csrpath):
if os.path.exists(src_letpath):
mw.execShell('rm -rf ' + src_letpath)
if os.path.exists(dst_csrpath):
mw.execShell('rm -rf ' + dst_csrpath)
if os.path.exists(dst_keypath):
mw.execShell('rm -rf ' + dst_keypath)
# mw.restartWeb()
return mw.returnJson(True, '已经删除SSL!')
# mw.restartWeb()
return mw.returnJson(False, '已经不存在SSL!')
# 申请面板let证书
def applyPanelLetSslApi(self):
# check domain is bind?
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
return mw.returnJson(False, '先要绑定域名!')
siteName = mw.readFile(bind_domain).strip()
auth_to = mw.getRunDir() + "/tmp"
@@ -404,6 +493,8 @@ class config_api:
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
is_already_apply = False
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
@@ -415,6 +506,8 @@ class config_api:
msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
return mw.returnJson(data['status'], msg, data['msg'])
else:
is_already_apply = True
mw.buildSoftLink(src_csrpath, dst_csrpath, True)
mw.buildSoftLink(src_keypath, dst_keypath, True)
@@ -426,6 +519,9 @@ class config_api:
if os.path.exists(tmp_well_know):
mw.execShell('rm -rf ' + tmp_well_know)
if is_already_apply:
return mw.returnJson(True, '重复申请!', data)
return mw.returnJson(True, '申请成功!', data)
def setPanelDomainApi(self):
@@ -509,8 +605,6 @@ class config_api:
return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
else:
try:
if not os.path.exists('ssl/input.ssl'):
mw.createSSL()
mw.writeFile(sslConf, 'True')
keyPath = mw.getRunDir() + '/ssl/private.pem'
@@ -647,9 +741,83 @@ class config_api:
else:
return False, ''
def setStatusCodeApi(self):
status_code = request.form.get('status_code', '').strip()
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))
mw.writeLog('面板设置', '将未授权响应状态码设置为:{}'.format(status_code))
return mw.returnJson(True, '设置成功!')
def getNotifyApi(self):
# 获取
data = mw.getNotifyData(True)
return mw.returnData(True, 'ok', data)
def setNotifyApi(self):
tag = request.form.get('tag', '').strip()
data = request.form.get('data', '').strip()
cfg = mw.getNotifyData(False)
crypt_data = mw.enDoubleCrypt(tag, data)
if tag in cfg:
cfg[tag]['cfg'] = crypt_data
else:
t = {'cfg': crypt_data}
cfg[tag] = t
mw.writeNotify(cfg)
return mw.returnData(True, '设置成功')
def setNotifyTestApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_data = request.form.get('data', '').strip()
if tag == 'tgbot':
t = json.loads(tag_data)
test_bool = mw.tgbotNotifyTest(t['app_token'], t['chat_id'])
if test_bool:
return mw.returnData(True, '验证成功')
return mw.returnData(False, '验证失败')
if tag == 'email':
t = json.loads(tag_data)
test_bool = mw.emailNotifyTest(t)
if test_bool:
return mw.returnData(True, '验证成功')
return mw.returnData(False, '验证失败')
return mw.returnData(False, '暂时未支持该验证')
def setNotifyEnableApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_enable = request.form.get('enable', '').strip()
data = mw.getNotifyData(False)
op_enable = True
op_action = '开启'
if tag_enable != 'true':
op_enable = False
op_action = '关闭'
if tag in data:
data[tag]['enable'] = op_enable
mw.writeNotify(data)
return mw.returnData(True, op_action + '成功')
def getPanelTokenApi(self):
api_file = self.__api_addr
tmp = mw.readFile(api_file)
if not os.path.exists(api_file):
ready_data = {"open": False, "token": "", "limit_addr": []}
@@ -668,7 +836,7 @@ class config_api:
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
data['token_crypt'] = mw.enCrypt(
data['token'], token).decode('utf-8')
data['token'], token)
mw.writeFile(api_file, json.dumps(data))
data['token'] = "***********************************"
@@ -680,10 +848,6 @@ class config_api:
def setPanelTokenApi(self):
op_type = request.form.get('op_type', '').strip()
api_file = self.__api_addr
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if op_type == '1':
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
@@ -693,7 +857,14 @@ class config_api:
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(True, 'ok', token)
elif op_type == '2':
api_file = self.__api_addr
if not os.path.exists(api_file):
return mw.returnJson(False, "先在API接口配置")
else:
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if op_type == '2':
data['open'] = not data['open']
stats = {True: '开启', False: '关闭'}
if not 'token_crypt' in data:
@@ -708,12 +879,38 @@ class config_api:
return mw.returnJson(not not data['open'], token)
elif op_type == '3':
limit_addr = request.form.get('limit_addr', '').strip()
data['limit_addr'] = limit_addr.split('\n')
mw.writeLog('API配置', '变更IP限制为[%s]' % limit_addr)
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(True, '保存成功!')
def renderUnauthorizedStatus(self, data):
cfg_unauth_status = 'data/unauthorized_status.pl'
if os.path.exists(cfg_unauth_status):
status_code = mw.readFile(cfg_unauth_status)
data['status_code'] = status_code
data['status_code_msg'] = status_code
if status_code == '0':
data['status_code_msg'] = "默认-安全入口错误提示"
elif status_code == '400':
data['status_code_msg'] = "400-客户端请求错误"
elif status_code == '401':
data['status_code_msg'] = "401-未授权访问"
elif status_code == '403':
data['status_code_msg'] = "403-拒绝访问"
elif status_code == '404':
data['status_code_msg'] = "404-页面不存在"
elif status_code == '408':
data['status_code_msg'] = "408-客户端超时"
elif status_code == '416':
data['status_code_msg'] = "416-无效的请求"
else:
data['status_code'] = '0'
data['status_code_msg'] = "默认-安全入口错误提示"
return data
def get(self):
data = {}
@@ -766,6 +963,8 @@ class config_api:
else:
data['bind_domain'] = ''
data = self.renderUnauthorizedStatus(data)
api_token = self.__api_addr
if os.path.exists(api_token):
bac = mw.readFile(api_token)
@@ -780,7 +979,9 @@ class config_api:
data['username'] = mw.M('users').where(
"id=?", (1,)).getField('username')
# databases hook 获取
data['hook_tag'] = request.args.get('tag', '')
# databases hook
database_hook_file = 'data/hook_database.json'
if os.path.exists(database_hook_file):
df = mw.readFile(database_hook_file)
@@ -789,7 +990,7 @@ class config_api:
else:
data['hook_database'] = []
# menu hook 获取
# menu hook
menu_hook_file = 'data/hook_menu.json'
if os.path.exists(menu_hook_file):
df = mw.readFile(menu_hook_file)
@@ -798,4 +999,23 @@ class config_api:
else:
data['hook_menu'] = []
# global_static hook
global_static_hook_file = 'data/hook_global_static.json'
if os.path.exists(global_static_hook_file):
df = mw.readFile(global_static_hook_file)
df = json.loads(df)
data['hook_global_static'] = df
else:
data['hook_global_static'] = []
# notiy config
notify_data = mw.getNotifyData(True)
notify_tag_list = ['tgbot', 'email']
for tag in notify_tag_list:
new_tag = 'notify_' + tag + '_enable'
data[new_tag] = ''
if tag in notify_data and 'enable' in notify_data[tag]:
if notify_data[tag]['enable']:
data[new_tag] = 'checked'
return data
+2 -2
View File
@@ -65,7 +65,7 @@ class Sql():
self.__DB_TABLE = table
return self
def where(self, where, param):
def where(self, where, param=()):
# WHERE条件
if where:
self.__OPT_WHERE = " WHERE " + where
@@ -348,7 +348,7 @@ class Sql():
except Exception as ex:
return "error: " + str(ex)
def query(self, sql, param):
def query(self, sql, param=()):
# 执行SQL语句返回数据集
self.__getConn()
try:
+132 -53
View File
@@ -247,8 +247,8 @@ class files_api:
os.remove(task_log)
return mw.returnJson(True, '任务已删除!')
# 上传文件
def uploadFileApi(self):
# 上传文件
from werkzeug.utils import secure_filename
from flask import request
@@ -263,6 +263,8 @@ class files_api:
if os.path.exists(filename):
s_path = filename
p_stat = os.stat(s_path)
# print(filename)
f.save(filename)
os.chown(filename, p_stat.st_uid, p_stat.st_gid)
os.chmod(filename, p_stat.st_mode)
@@ -271,6 +273,86 @@ class files_api:
mw.writeLog('文件管理', msg)
return mw.returnMsg(True, '上传成功!')
# 设置文件和目录权限
def setMode(self, path):
s_path = os.path.dirname(path)
p_stat = os.stat(s_path)
os.chown(path, p_stat.st_uid, p_stat.st_gid)
os.chmod(path, p_stat.st_mode)
def uploadSegmentApi(self):
# 分段上传
path = request.form.get('path', '')
name = request.form.get('name', '')
size = request.form.get('size')
start = request.form.get('start')
dir_mode = request.form.get('dir_mode', '')
file_mode = request.form.get('file_mode', '')
if not mw.fileNameCheck(name):
return mw.returnJson(False, '文件名中不能包含特殊字符!')
if path == '/':
return mw.returnJson(False, '不能直接上传文件到系统根目录!')
if name.find('./') != -1 or path.find('./') != -1:
return mw.returnJson(False, '错误的参数')
if not os.path.exists(path):
os.makedirs(path, 493)
if not dir_mode != '' or not file_mode != '':
mw.setMode(path)
save_path = os.path.join(
path, name + '.' + str(int(size)) + '.upload.tmp')
d_size = 0
if os.path.exists(save_path):
d_size = os.path.getsize(save_path)
if d_size != int(start):
return str(d_size)
f = open(save_path, 'ab')
b64_data = request.form.get('b64_data', '0')
if b64_data == '1':
import base64
b64_data = base64.b64decode(args.b64_data)
f.write(b64_data)
else:
upload_files = request.files.getlist("blob")
for tmp_f in upload_files:
f.write(tmp_f.read())
f.close()
f_size = os.path.getsize(save_path)
if f_size != int(size):
return str(f_size)
new_name = os.path.join(path, name)
if os.path.exists(new_name):
if new_name.find('.user.ini') != -1:
mw.execShell("chattr -i " + new_name)
try:
os.remove(new_name)
except:
mw.execShell("rm -f %s" % new_name)
os.renames(save_path, new_name)
if dir_mode != '' and dir_mode != '':
mode_tmp1 = dir_mode.split(',')
mw.setMode(path, mode_tmp1[0])
mw.setOwn(path, mode_tmp1[1])
mode_tmp2 = file_mode.split(',')
mw.setMode(new_name, mode_tmp2[0])
mw.setOwn(new_name, mode_tmp2[1])
else:
self.setMode(new_name)
msg = mw.getInfo('上传文件[{1}] 到 [{2}]成功!', (new_name, path))
mw.writeLog('文件管理', msg)
return mw.returnMsg(True, '上传成功!')
def getRecycleBinApi(self):
rPath = self.rPath
if not os.path.exists(rPath):
@@ -626,7 +708,7 @@ class files_api:
return not path in nDirs
def getDirSize(self, path):
if mw.getOs() == 'darwin':
if mw.isAppleSystem():
tmp = mw.execShell('du -sh ' + path)
else:
tmp = mw.execShell('du -sbh ' + path)
@@ -677,56 +759,29 @@ class files_api:
if os.path.getsize(path) > 2097152:
return mw.returnJson(False, '不能在线编辑大于2MB的文件!')
if os.path.isdir(path):
return mw.returnJson(False, '这不是一个文件!')
fp = open(path, 'rb')
data = {}
data['status'] = True
try:
if fp:
from chardet.universaldetector import UniversalDetector
detector = UniversalDetector()
srcBody = b""
for line in fp.readlines():
detector.feed(line)
srcBody += line
detector.close()
char = detector.result
data['encoding'] = char['encoding']
if char['encoding'] == 'GB2312' or not char['encoding'] or char[
'encoding'] == 'TIS-620' or char['encoding'] == 'ISO-8859-9':
data['encoding'] = 'GBK'
if char['encoding'] == 'ascii' or char[
'encoding'] == 'ISO-8859-1':
data['encoding'] = 'utf-8'
if char['encoding'] == 'Big5':
data['encoding'] = 'BIG5'
if not data['encoding'] in ['GBK', 'utf-8', 'BIG5']:
data['encoding'] = 'utf-8'
if fp:
srcBody = fp.read()
fp.close()
encoding_list = ['utf-8', 'GBK', 'BIG5']
for el in encoding_list:
try:
if sys.version_info[0] == 2:
data['data'] = srcBody.decode(
data['encoding']).encode('utf-8', errors='ignore')
else:
data['data'] = srcBody.decode(data['encoding'])
except:
data['encoding'] = char['encoding']
if sys.version_info[0] == 2:
data['data'] = srcBody.decode(
data['encoding']).encode('utf-8', errors='ignore')
else:
data['data'] = srcBody.decode(data['encoding'])
return mw.returnJson(True, 'OK', data)
else:
if sys.version_info[0] == 2:
data['data'] = srcBody.decode('utf-8').encode('utf-8')
else:
data['data'] = srcBody.decode('utf-8')
data['encoding'] = 'utf-8'
data['encoding'] = el
data['data'] = srcBody.decode(data['encoding'])
break
except Exception as ex:
if el == 'BIG5':
return mw.returnJson(False, '文件编码不被兼容,无法正确读取文件!' + str(ex))
else:
return mw.returnJson(False, '文件未正常打开!')
return mw.returnJson(True, 'OK', data)
except Exception as ex:
return mw.returnJson(False, '文件编码不被兼容,无法正确读取文件!' + str(ex))
return mw.returnJson(True, 'OK', data)
def saveBody(self, path, data, encoding='utf-8'):
if not os.path.exists(path):
@@ -734,13 +789,10 @@ class files_api:
try:
if encoding == 'ascii':
encoding = 'utf-8'
if sys.version_info[0] == 2:
data = data.encode(encoding, errors='ignore')
fp = open(path, 'w+')
else:
data = data.encode(
encoding, errors='ignore').decode(encoding)
fp = open(path, 'w+', encoding=encoding)
data = data.encode(
encoding, errors='ignore').decode(encoding)
fp = open(path, 'w+', encoding=encoding)
fp.write(data)
fp.close()
@@ -935,6 +987,33 @@ class files_api:
return mw.getJson(data)
def execShellApi(self):
# 执行SHELL命令
shell = request.form.get('shell', '').strip()
path = request.form.get('path', '').strip()
disabled = ['vi', 'vim', 'top', 'passwd', 'su']
tmp = shell.split(' ')
if tmp[0] in disabled:
return mw.returnJson(False, '禁止执行[{}]'.format(tmp[0]))
shellStr = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
cd %s
%s
''' % (path, shell)
mw.writeFile('/tmp/panelShell.sh', shellStr)
mw.execShell(
'nohup bash /tmp/panelShell.sh > /tmp/panelShell.pl 2>&1 &')
return mw.returnJson(True, 'ok')
def getExecShellMsgApi(self):
# 取SHELL执行结果
fileName = '/tmp/panelShell.pl'
if not os.path.exists(fileName):
return ''
status = not mw.processExists('bash', None, '/tmp/panelShell.sh')
return mw.returnJson(status, mw.getNumLines(fileName, 200))
def __get_stats(self, filename, path=None):
filename = filename.replace('//', '/')
try:
+14 -13
View File
@@ -34,13 +34,13 @@ class firewall_api:
def __init__(self):
iptables_file = mw.systemdCfgDir() + '/iptables.service'
if os.path.exists(iptables_file):
self.__isIptables = True
if os.path.exists('/usr/sbin/firewalld'):
self.__isFirewalld = True
if os.path.exists('/usr/sbin/ufw'):
elif os.path.exists('/usr/sbin/ufw'):
self.__isUfw = True
if mw.isAppleSystem():
elif os.path.exists(iptables_file):
self.__isIptables = True
elif mw.isAppleSystem():
self.__isMac = True
##### ----- start ----- ###
@@ -123,12 +123,12 @@ class firewall_api:
address = port
if self.__isUfw:
mw.execShell('ufw delete deny from ' + address + ' to any')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
elif self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
else:
pass
@@ -149,14 +149,15 @@ class firewall_api:
return mw.returnJson(False, '失败,不能删除当前面板端口!')
if self.__isUfw:
mw.execShell('ufw delete allow ' + port + '/tcp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
elif self.__isFirewalld:
port = port.replace(':', '-')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
else:
pass
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
@@ -438,13 +439,13 @@ class firewall_api:
def addAcceptPort(self, port):
if self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
elif self.__isFirewalld:
port = port.replace(':', '-')
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
mw.execShell(cmd)
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
else:
pass
return True
+508 -12
View File
@@ -22,10 +22,14 @@ import hashlib
import shlex
import datetime
import subprocess
import glob
import base64
import re
import db
from random import Random
import db
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
@@ -80,6 +84,10 @@ def getPanelDataDir():
return getRunDir() + '/data'
def getPanelTmp():
return getRunDir() + '/tmp'
def getServerDir():
return getRootDir() + '/server'
@@ -123,6 +131,23 @@ def getAcmeDir():
return acme
def getAcmeDomainDir(domain):
acme_dir = getAcmeDir()
acme_domain = acme_dir + '/' + domain
acme_domain_ecc = acme_domain + '_ecc'
if os.path.exists(acme_domain_ecc):
acme_domain = acme_domain_ecc
return acme_domain
def fileNameCheck(filename):
f_strs = [';', '&', '<', '>']
for fs in f_strs:
if filename.find(fs) != -1:
return False
return True
def triggerTask():
isTask = getRunDir() + '/tmp/panelTask.pl'
writeFile(isTask, 'True')
@@ -228,6 +253,14 @@ def isIpAddr(ip):
return False
def getWebStatus():
pid = getServerDir() + '/openresty/nginx/logs/nginx.pid'
if os.path.exists(pid):
return True
return False
# ------------------------------ openresty start -----------------------------
def restartWeb():
return opWeb("reload")
@@ -252,6 +285,63 @@ def opWeb(method):
return False
def opLuaMake(cmd_name):
path = getServerDir() + '/web_conf/nginx/lua/lua.conf'
root_dir = getServerDir() + '/web_conf/nginx/lua/' + cmd_name
dst_path = getServerDir() + '/web_conf/nginx/lua/' + cmd_name + '.lua'
def_path = getServerDir() + '/web_conf/nginx/lua/empty.lua'
if not os.path.exists(root_dir):
execShell('mkdir -p ' + root_dir)
files = []
for fl in os.listdir(root_dir):
suffix = getFileSuffix(fl)
if suffix != 'lua':
continue
flpath = os.path.join(root_dir, fl)
files.append(flpath)
if len(files) > 0:
def_path = dst_path
content = ''
for f in files:
t = readFile(f)
f_base = os.path.basename(f)
content += '-- ' + '*' * 20 + ' ' + f_base + ' start ' + '*' * 20 + "\n"
content += t
content += "\n" + '-- ' + '*' * 20 + ' ' + f_base + ' end ' + '*' * 20 + "\n"
writeFile(dst_path, content)
else:
if os.path.exists(dst_path):
os.remove(dst_path)
conf = readFile(path)
conf = re.sub(cmd_name + ' (.*);',
cmd_name + " " + def_path + ";", conf)
writeFile(path, conf)
def opLuaInitFile():
opLuaMake('init_by_lua_file')
def opLuaInitWorkerFile():
opLuaMake('init_worker_by_lua_file')
def opLuaInitAccessFile():
opLuaMake('access_by_lua_file')
def opLuaMakeAll():
opLuaInitFile()
opLuaInitWorkerFile()
opLuaInitAccessFile()
# ------------------------------ openresty end -----------------------------
def restartMw():
import system_api
system_api.system_api().restartMw()
@@ -454,6 +544,14 @@ def getDate():
return time.strftime('%Y-%m-%d %X', time.localtime())
def getDateFromNow(tf_format="%Y-%m-%d %H:%M:%S", time_zone="Asia/Shanghai"):
# 取格式时间
import time
os.environ['TZ'] = time_zone
time.tzset()
return time.strftime(tf_format, time.localtime())
def getDataFromInt(val):
time_format = '%Y-%m-%d %H:%M:%S'
time_str = time.localtime(val)
@@ -462,15 +560,44 @@ def getDataFromInt(val):
def writeLog(stype, msg, args=()):
# 写日志
uid = 1
try:
from flask import session
uid = 1
if 'uid' in session:
uid = session['uid']
return writeDbLog(stype, msg, args, uid)
except Exception as e:
print(getTracebackInfo())
return False
pass
# writeFileLog(getTracebackInfo())
return writeDbLog(stype, msg, args, uid)
def writeFileLog(msg, path=None, limit_size=50 * 1024 * 1024, save_limit=3):
log_file = getServerDir() + '/mdserver-web/logs/debug.log'
if path != None:
log_file = path
if os.path.exists(log_file):
size = os.path.getsize(log_file)
if size > limit_size:
log_file_rename = log_file + "_" + \
time.strftime("%Y-%m-%d_%H%M%S") + '.log'
os.rename(log_file, log_file_rename)
logs = sorted(glob.glob(log_file + "_*"))
count = len(logs)
save_limit = count - save_limit
for i in range(count):
if i > save_limit:
break
os.remove(logs[i])
# print('|---多余日志[' + logs[i] + ']已删除!')
f = open(log_file, 'ab+')
msg += "\n"
if __name__ == '__main__':
print(msg)
f.write(msg.encode('utf-8'))
f.close()
return True
def writeDbLog(stype, msg, args=(), uid=1):
@@ -577,6 +704,44 @@ def dePunycode(domain):
def enCrypt(key, strings):
# 加密字符串
try:
import base64
_key = key.encode('utf-8')
_key = base64.urlsafe_b64encode(_key)
if type(strings) != bytes:
strings = strings.encode('utf-8')
import cryptography
from cryptography.fernet import Fernet
f = Fernet(_key)
result = f.encrypt(strings)
return result.decode('utf-8')
except:
writeFileLog(getTracebackInfo())
return strings
def deCrypt(key, strings):
# 解密字符串
try:
import base64
_key = key.encode('utf-8')
_key = base64.urlsafe_b64encode(_key)
if type(strings) != bytes:
strings = strings.encode('utf-8')
from cryptography.fernet import Fernet
f = Fernet(_key)
result = f.decrypt(strings).decode('utf-8')
return result
except:
writeFileLog(getTracebackInfo())
return strings
def enDoubleCrypt(key, strings):
# 加密字符串
try:
import base64
@@ -591,11 +756,11 @@ def enCrypt(key, strings):
result = f.encrypt(strings)
return result.decode('utf-8')
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
def deCrypt(key, strings):
def deDoubleCrypt(key, strings):
# 解密字符串
try:
import base64
@@ -609,10 +774,137 @@ def deCrypt(key, strings):
result = f.decrypt(strings).decode('utf-8')
return result
except:
print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return strings
def aesEncrypt(data, key='ABCDEFGHIJKLMNOP', vi='0102030405060708'):
# aes加密
# @param data 被加密的数据
# @param key 加解密密匙 16位
# @param vi 16位
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
if not isinstance(data, bytes):
data = data.encode()
# AES_CBC_KEY = os.urandom(32)
# AES_CBC_IV = os.urandom(16)
AES_CBC_KEY = key.encode()
AES_CBC_IV = vi.encode()
# print("AES_CBC_KEY:", AES_CBC_KEY)
# print("AES_CBC_IV:", AES_CBC_IV)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(data) + padder.finalize()
cipher = Cipher(algorithms.AES(AES_CBC_KEY),
modes.CBC(AES_CBC_IV),
backend=default_backend())
encryptor = cipher.encryptor()
edata = encryptor.update(padded_data)
# print(edata)
# print(str(edata))
# print(edata.decode())
return edata
def aesDecrypt(data, key='ABCDEFGHIJKLMNOP', vi='0102030405060708'):
# aes加密
# @param data 被解密的数据
# @param key 加解密密匙 16位
# @param vi 16位
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
if not isinstance(data, bytes):
data = data.encode()
AES_CBC_KEY = key.encode()
AES_CBC_IV = vi.encode()
cipher = Cipher(algorithms.AES(AES_CBC_KEY),
modes.CBC(AES_CBC_IV),
backend=default_backend())
decryptor = cipher.decryptor()
ddata = decryptor.update(data)
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
data = unpadder.update(ddata)
try:
uppadded_data = data + unpadder.finalize()
except ValueError:
raise Exception('无效的加密信息!')
return uppadded_data
def aesEncrypt_Crypto(data, key, vi):
# 该方法保留,暂时不使用
# aes加密
# @param data 被加密的数据
# @param key 加解密密匙 16位
# @param vi 16位
from Crypto.Cipher import AES
cryptor = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
# 判断是否含有中文
zhmodel = re.compile(u'[\u4e00-\u9fff]')
match = zhmodel.search(data)
if match == None:
# 无中文时
add = 16 - len(data) % 16
pad = lambda s: s + add * chr(add)
data = pad(data)
enctext = cryptor.encrypt(data.encode('utf8'))
else:
# 含有中文时
data = data.encode()
add = 16 - len(data) % 16
data = data + add * (chr(add)).encode()
enctext = cryptor.encrypt(data)
encodestrs = base64.b64encode(enctext).decode('utf8')
return encodestrs
def aesDecrypt_Crypto(data, key, vi):
# 该方法保留,暂时不使用
# aes加密
# @param data 被加密的数据
# @param key 加解密密匙 16位
# @param vi 16位
from crypto.Cipher import AES
data = data.encode('utf8')
encodebytes = base64.urlsafe_b64decode(data)
cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
text_decrypted = cipher.decrypt(encodebytes)
# 判断是否含有中文
zhmodel = re.compile(u'[\u4e00-\u9fff]')
match = zhmodel.search(text_decrypted)
if match == False:
# 无中文时补位
unpad = lambda s: s[0:-s[-1]]
text_decrypted = unpad(text_decrypted)
text_decrypted = text_decrypted.decode('utf8').rstrip() # 去掉补位的右侧空格
return text_decrypted
def buildSoftLink(src, dst, force=False):
'''
建立软连接
@@ -885,7 +1177,7 @@ def getLocalIp():
try:
ipaddress = readFile(filename)
if not ipaddress or ipaddress == '127.0.0.1':
cmd = "curl -4 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
cmd = "curl --insecure -4 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
ip = execShell(cmd)
result = ip[0].strip()
if result == '':
@@ -894,7 +1186,7 @@ def getLocalIp():
return result
return ipaddress
except Exception as e:
cmd = "curl -6 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
cmd = "curl --insecure -6 -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text"
ip = execShell(cmd)
result = ip[0].strip()
if result == '':
@@ -1019,6 +1311,15 @@ def setOwn(filename, user, group=None):
return True
def setMode(filename, mode):
# 设置文件权限
if not os.path.exists(filename):
return False
mode = int(str(mode), 8)
os.chmod(filename, mode)
return True
def checkPort(port):
# 检查端口是否合法
ports = ['21', '443', '888']
@@ -1104,7 +1405,7 @@ def makeConf():
file = getRunDir() + '/data/json/config.json'
if not os.path.exists(file):
c = {}
c['title'] = '大圣面板'
c['title'] = '金灵面板'
c['home'] = 'http://github/midoks/mdserver-web'
c['recycle_bin'] = True
c['template'] = 'default'
@@ -1404,7 +1705,7 @@ def getCertName(certPath):
result['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
return result
except Exception as e:
# print(getTracebackInfo())
writeFileLog(getTracebackInfo())
return None
@@ -1502,6 +1803,176 @@ def getMyORMDb():
o = ormDb.ORM()
return o
##################### notify start #########################################
def initNotifyConfig():
p = getNotifyPath()
if not os.path.exists(p):
writeFile(p, '{}')
return True
def getNotifyPath():
path = 'data/notify.json'
return path
def getNotifyData(is_parse=False):
initNotifyConfig()
notify_file = getNotifyPath()
notify_data = readFile(notify_file)
data = json.loads(notify_data)
if is_parse:
tag_list = ['tgbot', 'email']
for t in tag_list:
if t in data and 'cfg' in data[t]:
data[t]['data'] = json.loads(deDoubleCrypt(t, data[t]['cfg']))
return data
def writeNotify(data):
p = getNotifyPath()
return writeFile(p, json.dumps(data))
def tgbotNotifyChatID():
data = getNotifyData(True)
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
return t['chat_id']
return ''
def tgbotNotifyObject():
data = getNotifyData(True)
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
import telebot
bot = telebot.TeleBot(app_token)
return True, bot
return False, None
def tgbotNotifyMessage(app_token, chat_id, msg):
import telebot
bot = telebot.TeleBot(app_token)
try:
data = bot.send_message(chat_id, msg)
return True
except Exception as e:
writeFileLog(str(e))
return False
def tgbotNotifyHttpPost(app_token, chat_id, msg):
try:
url = 'https://api.telegram.org/bot' + app_token + '/sendMessage'
post_data = {
'chat_id': chat_id,
'text': msg,
}
rdata = httpPost(url, post_data)
return True
except Exception as e:
writeFileLog(str(e))
return False
def tgbotNotifyTest(app_token, chat_id):
msg = 'MW-通知验证测试OK'
return tgbotNotifyHttpPost(app_token, chat_id, msg)
def emailNotifyMessage(data):
'''
邮件通知
'''
sys.path.append(os.getcwd() + "/class/plugin")
import memail
try:
if data['smtp_ssl'] == 'ssl':
memail.sendSSL(data['smtp_host'], data['smtp_port'],
data['username'], data['password'],
data['to_mail_addr'], data['subject'], data['content'])
else:
memail.send(data['smtp_host'], data['smtp_port'],
data['username'], data['password'],
data['to_mail_addr'], data['subject'], data['content'])
return True
except Exception as e:
print(getTracebackInfo())
return False
def emailNotifyTest(data):
# print(data)
data['subject'] = 'MW通知测试'
data['content'] = data['mail_test']
return emailNotifyMessage(data)
def notifyMessageTry(msg, stype='common', trigger_time=300, is_write_log=True):
lock_file = getPanelTmp() + '/notify_lock.json'
if not os.path.exists(lock_file):
writeFile(lock_file, '{}')
lock_data = json.loads(readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False
else:
lock_data[stype] = {'do_time': time.time()}
writeFile(lock_file, json.dumps(lock_data))
if is_write_log:
writeLog("通知管理[" + stype + "]", msg)
data = getNotifyData(True)
# tag_list = ['tgbot', 'email']
# tagbot
do_notify = False
if 'tgbot' in data and 'enable' in data['tgbot']:
if data['tgbot']['enable']:
t = data['tgbot']['data']
i = sys.version_info
# telebot 在python小于3.7无法使用
if i[0] < 3 or i[1] < 7:
do_notify = tgbotNotifyHttpPost(
t['app_token'], t['chat_id'], msg)
else:
do_notify = tgbotNotifyMessage(
t['app_token'], t['chat_id'], msg)
if 'email' in data and 'enable' in data['email']:
if data['email']['enable']:
t = data['email']['data']
t['subject'] = 'MW通知'
t['content'] = msg
do_notify = emailNotifyMessage(t)
return do_notify
def notifyMessage(msg, stype='common', trigger_time=300, is_write_log=True):
try:
return notifyMessageTry(msg, stype, trigger_time, is_write_log)
except Exception as e:
writeFileLog(getTracebackInfo())
return False
##################### notify end #########################################
##################### ssh start #########################################
def getSshDir():
@@ -1511,6 +1982,31 @@ def getSshDir():
return '/root/.ssh'
def processExists(pname, exe=None, cmdline=None):
# 进程是否存在
try:
import psutil
pids = psutil.pids()
for pid in pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe and not cmdline:
return True
else:
if exe:
if p.exe() == exe:
return True
if cmdline:
if cmdline in p.cmdline():
return True
except:
pass
return False
except:
return True
def createRsa():
# ssh-keygen -t rsa -P "" -C "midoks@163.com"
ssh_dir = getSshDir()
+32 -13
View File
@@ -71,8 +71,9 @@ class plugins_api:
if not mw.isNumber(sType):
sType = 0
# print sPage
data = self.getPluginList(sType, int(sPage))
# print(sPage, sType)
search = request.args.get('search', '').lower()
data = self.getPluginList(sType, search, int(sPage))
return mw.getJson(data)
def menuGetAbsPath(self, tag, path):
@@ -91,7 +92,7 @@ class plugins_api:
t = mw.readFile(menu_file)
tlist = json.loads(t)
for menu_data in tlist:
if 'path' in menu_data:
if tag == menu_data['name'] and 'path' in menu_data:
tpath = self.menuGetAbsPath(tag, menu_data['path'])
content = mw.readFile(tpath)
data['plugin_content'] = content
@@ -256,13 +257,14 @@ class plugins_api:
data = json.loads(t)
for idx in range(len(data)):
if data[idx]['title'] == info['title'] and data[idx]['name'] == info['name']:
if data[idx]['name'] == info['name']:
data.remove(data[idx])
break
mw.writeFile(hookPath, json.dumps(data))
def hookInstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
valid_list_hook = ['menu', 'global_static', 'site_cb']
if 'hook' in info:
hooks = info['hook']
for h in hooks:
@@ -280,7 +282,7 @@ class plugins_api:
def hookUninstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
valid_list_hook = ['menu', 'global_static', 'site_cb']
if 'hook' in info:
hooks = info['hook']
for h in hooks:
@@ -780,7 +782,18 @@ class plugins_api:
print(e)
return plugins_info
def getAllListPage(self, sType='0', page=1, pageSize=10):
def searchKey(self, info, kw):
try:
if info['title'].lower().find(kw) > -1:
return True
if info['ps'].lower().find(kw) > -1:
return True
if info['name'].lower().find(kw) > -1:
return True
except Exception as e:
return False
def getAllListPage(self, sType='0', kw='', page=1, pageSize=10):
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
@@ -791,11 +804,14 @@ class plugins_api:
if os.path.exists(json_file):
try:
data = json.loads(mw.readFile(json_file))
# 判断是否搜索
if kw != '' and not self.searchKey(data, kw):
continue
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception as e:
print(e)
print(mw.getTracebackInfo())
start = (page - 1) * pageSize
end = start + pageSize
@@ -925,14 +941,14 @@ class plugins_api:
return plugins_info
def getPluginList(self, sType, sPage=1, sPageSize=10):
# print sType, sPage, sPageSize
def getPluginList(self, sType, kw='', sPage=1, sPageSize=10):
# print(sType, kw, sPage, sPageSize)
ret = {}
ret['type'] = json.loads(mw.readFile(self.__type))
# plugins_info = self.getAllListThread(sType)
# plugins_info = self.getAllListProcess(sType)
data = self.getAllListPage(sType, sPage, sPageSize)
data = self.getAllListPage(sType, kw, sPage, sPageSize)
ret['data'] = data[0]
args = {}
@@ -1014,8 +1030,11 @@ class plugins_api:
# shell 调用
def run(self, name, func, version='', args='', script='index'):
path = self.__plugin_dir + \
'/' + name + '/' + script + '.py'
path = self.__plugin_dir + '/' + name + '/' + script + '.py'
if not os.path.exists(path):
path = self.__plugin_dir + '/' + name + '/' + name + '.py'
py = 'python3 ' + path
if args == '':
+64 -15
View File
@@ -72,24 +72,60 @@ class site_api:
mw.execShell("mkdir -p " + self.sslLetsDir +
" && chmod -R 755 " + self.sslLetsDir)
def runHook(self, hook_name, func_name):
# 站点操作Hook
hook_file = 'data/hook_site_cb.json'
hook_cfg = []
if os.path.exists(hook_file):
t = mw.readFile(hook_file)
hook_cfg = json.loads(t)
hook_num = len(hook_cfg)
if hook_num == 0:
return
import plugins_api
pa = plugins_api.plugins_api()
for x in range(hook_num):
hook_data = hook_cfg[x]
if func_name in hook_data:
app_name = hook_data["name"]
run_func = hook_data[func_name]['func']
# print(app_name, run_func)
pa.run(app_name, run_func)
return True
##### ----- start ----- ###
def listApi(self):
limit = request.form.get('limit', '10')
p = request.form.get('p', '1')
type_id = request.form.get('type_id', '0').strip()
search = request.form.get('search', '').strip()
start = (int(p) - 1) * (int(limit))
siteM = mw.M('sites').field('id,name,path,status,ps,addtime,edate')
if type_id != '' and int(type_id) >= 0:
siteM.where('type_id=?', (type_id,))
sql_where = ''
if search != '':
sql_where = " name like '%" + search + "%' or ps like '%" + search + "%' "
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:
sql_where = " type_id=" + type_id
if sql_where != '':
siteM.where(sql_where)
_list = siteM.limit((str(start)) + ',' +
limit).order('id desc').select()
for i in range(len(_list)):
_list[i]['backup_count'] = mw.M('backup').where(
"pid=? AND type=?", (_list[i]['id'], 0)).count()
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()
_ret = {}
_ret['data'] = _list
@@ -550,7 +586,7 @@ class site_api:
return mw.returnJson(False, '使用中,先关闭再删除')
mw.execShell('rm -rf ' + ssl_lets_dir)
elif ssl_type == 'acme':
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name
ssl_acme_dir = mw.getAcmeDomainDir(site_name)
csr_acme_path = ssl_acme_dir + '/fullchain.cer' # 生成证书路径
if mw.md5(mw.readFile(csr_acme_path)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '使用中,先关闭再删除')
@@ -587,9 +623,9 @@ class site_api:
csr_path = self.sslLetsDir + '/' + site_name + '/fullchain.pem' # 生成证书路径
key_path = self.sslLetsDir + '/' + site_name + '/privkey.pem' # 密钥文件路径
elif ssl_type == 'acme':
csr_path = mw.getAcmeDir() + '/' + site_name + '/fullchain.cer' # 生成证书路径
key_path = mw.getAcmeDir() + '/' + site_name + '/' + \
site_name + '.key' # 密钥文件路径
acme_dir = mw.getAcmeDomainDir(site_name)
csr_path = acme_dir + '/fullchain.cer' # 生成证书路径
key_path = acme_dir + '/' + site_name + '.key' # 密钥文件路径
key = mw.readFile(key_path)
csr = mw.readFile(csr_path)
@@ -751,6 +787,9 @@ class site_api:
mw.execShell('echo "lets" > "' + path + '/README"')
elif ssl_type == 'acme':
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name
if not os.path.exists(ssl_acme_dir):
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name + '_ecc'
acme_csrpath = ssl_acme_dir + '/fullchain.cer'
acme_keypath = ssl_acme_dir + '/' + site_name + '.key'
if mw.md5(mw.readFile(acme_csrpath)) == mw.md5(mw.readFile(csr_path)):
@@ -989,16 +1028,17 @@ class site_api:
# print(cmd)
result = mw.execShell(cmd)
src_path = acme_dir + '/' + domains[0]
src_path = mw.getAcmeDomainDir(domains[0])
src_cert = src_path + '/fullchain.cer'
src_key = src_path + '/' + domains[0] + '.key'
src_cert.replace("\*", "*")
msg = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
<p>2、检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
<p>3、如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
<p>4、如果您的站点设置了301重定向,请先将其关闭</p>\
<p>5、如果以上检查都确认没有问题,请尝试更换DNS服务商</p>'
if not os.path.exists(src_cert.replace("\*", "*")):
if not os.path.exists(src_cert):
data = {}
data['err'] = result
data['out'] = result[0]
@@ -1271,6 +1311,7 @@ class site_api:
mw.M('domain').add('pid,name,port,addtime',
(pid, domain_name, domain_port, mw.getDate()))
self.runHook('site_cb', 'add')
return mw.returnJson(True, '域名添加成功!')
def addDirBindApi(self):
@@ -1394,13 +1435,15 @@ class site_api:
data['data'] = mw.readFile(filename)
data['rlist'] = []
for ds in os.listdir(self.rewritePath):
if ds[0:1] == '.':
continue
if ds == 'list.txt':
continue
data['rlist'].append(ds[0:len(ds) - 5])
data['filename'] = filename
return mw.getJson(data)
# 修改物理路径
# 修改物理路径
def setPathApi(self):
mid = request.form.get('id', '')
path = request.form.get('path', '')
@@ -2529,16 +2572,18 @@ location ^~ {from} {\n\
self.createRootDir(self.sitePath)
self.nginxAddConf()
mw.M('domain').add('pid,name,port,addtime',
(pid, self.siteName, self.sitePort, mw.getDate()))
# 添加更多域名
for domain in siteMenu['domainlist']:
self.addDomain(domain, self.siteName, pid)
mw.M('domain').add('pid,name,port,addtime',
(pid, self.siteName, self.sitePort, mw.getDate()))
data = {}
data['siteStatus'] = False
mw.restartWeb()
self.runHook('site_cb', 'add')
return mw.returnJson(True, '添加成功')
def deleteWSLogs(self, webname):
@@ -2588,6 +2633,8 @@ location ^~ {from} {\n\
mw.execShell('rm -rf ' + ssl_acme_dir)
mw.M('sites').where("id=?", (sid,)).delete()
mw.M('domain').where("pid=?", (sid,)).delete()
mw.M('domain').where("name=?", (webname,)).delete()
# binding domain delete
binding_list = mw.M('binding').field(
@@ -2605,6 +2652,8 @@ location ^~ {from} {\n\
mw.M('binding').where("pid=?", (sid,)).delete()
mw.restartWeb()
self.runHook('site_cb', 'delete')
return mw.returnJson(True, '站点删除成功!')
def setEndDate(self, sid, edate):
+1 -1
View File
@@ -320,7 +320,7 @@ class ssh_terminal:
def getSshInfo(self, file):
rdata = mw.readFile(file)
destr = mw.deCrypt('mdserver-web', rdata)
destr = mw.enDoubleCrypt('mdserver-web', rdata)
return json.loads(destr)
def setAttr(self, sid, info):
+57
View File
@@ -166,6 +166,33 @@ class system_api:
except:
return False
def getEnvInfoApi(self, get=None):
serverInfo = {}
serverInfo['status'] = True
sdir = mw.getServerDir()
serverInfo['webserver'] = '未安装'
if os.path.exists(sdir + '/openresty/nginx/sbin/nginx'):
serverInfo['webserver'] = 'OpenResty'
serverInfo['php'] = []
phpversions = ['52', '53', '54', '55', '56', '70', '71',
'72', '73', '74', '80', '81', '82', '83', '84']
phpPath = sdir + '/php/'
for pv in phpversions:
if not os.path.exists(phpPath + pv + '/bin/php'):
continue
serverInfo['php'].append(pv)
serverInfo['mysql'] = False
if os.path.exists(sdir + '/mysql/bin/mysql'):
serverInfo['mysql'] = True
import psutil
try:
diskInfo = psutil.disk_usage('/www')
except:
diskInfo = psutil.disk_usage('/')
serverInfo['disk'] = diskInfo[2]
return mw.returnJson(True, 'ok', serverInfo)
def getPanelInfo(self, get=None):
# 取面板配置
address = mw.GetLocalIp()
@@ -724,6 +751,36 @@ class system_api:
mw.execShell('rm -rf ' + toPath + '/mdserver-web-' + version)
mw.execShell('rm -rf ' + toPath + '/mw.zip')
update_env = '''
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
P_VER=`python3 -V | awk '{print $2}'`
if [ ! -f /www/server/mdserver-web/bin/activate ];then
cd /www/server/mdserver-web && python3 -m venv .
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
else
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
fi
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
PIPSRC="https://pypi.python.org/simple"
if [ ! -z "$cn" ];then
PIPSRC="https://pypi.tuna.tsinghua.edu.cn/simple"
fi
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/requirements.txt -i $PIPSRC
P_VER_D=`echo "$P_VER"|awk -F '.' '{print $1}'`
P_VER_M=`echo "$P_VER"|awk -F '.' '{print $2}'`
NEW_P_VER=${P_VER_D}.${P_VER_M}
if [ -f /www/server/mdserver-web/version/r${NEW_P_VER}.txt ];then
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/version/r${NEW_P_VER}.txt -i $PIPSRC
fi
'''
os.system(update_env)
self.restartMw()
return mw.returnJson(True, '安装更新成功!')
+48
View File
@@ -0,0 +1,48 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# VIP用户管理
# ---------------------------------------------------------------------------------
import mw
from flask import request
import requests
class vip_api:
api_url = 'https://wo.midoks.me/api/wp-json/vip'
def __init__(self):
pass
def loginApi(self):
username = request.form.get('username', '')
password = request.form.get('password', '')
password = mw.aesEncrypt(password)
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
print("name:", str(username))
print("pwd:", str(password))
args = {
'name': username,
'pass': password
}
data = requests.post(self.api_url + '/v1/login',
data=args, headers=headers)
print(data.text)
return mw.returnJson(False, "测试中!")
+43
View File
@@ -0,0 +1,43 @@
# coding: utf-8
import smtplib
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
def send(smtp_host, smtp_port, username, password, to_mail, subject, content):
smtp = smtplib.SMTP()
smtp.connect(smtp_host, port=smtp_port)
smtp.login(user=username, password=password)
msg = MIMEText(content, 'plain', 'utf-8')
msg['From'] = _format_addr(username)
msg['To'] = _format_addr(to_mail)
msg['Subject'] = Header(subject, 'utf-8').encode()
smtp.sendmail(from_addr=username, to_addrs=to_mail, msg=msg.as_string())
return True
def sendSSL(smtp_host, smtp_port, username, password, to_mail, subject, content):
smtp = smtplib.SMTP_SSL(smtp_host, port=smtp_port)
smtp.login(user=username, password=password)
msg = MIMEText(content, 'plain', 'utf-8')
msg['From'] = _format_addr(username)
msg['To'] = _format_addr(to_mail)
msg['Subject'] = Header(subject, 'utf-8').encode()
smtp.sendmail(from_addr=username, to_addrs=to_mail, msg=msg.as_string())
smtp.quit()
return True
+3
View File
@@ -65,6 +65,9 @@ class ORM:
def setCharset(self, charset):
self.__DB_CHARSET = charset
def setHost(self, host):
self.__DB_HOST = host
def setPort(self, port):
self.__DB_PORT = port
+10 -10
View File
@@ -16,21 +16,21 @@ mw_start_task()
{
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "Starting mw-tasks... \c"
echo -e "starting mw-tasks... \c"
cd $DIR && python3 task.py >> ${DIR}/logs/task.log 2>&1 &
sleep 0.3
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $DIR/logs/task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
return;
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $DIR/logs/task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
echo "starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
fi
}
@@ -62,14 +62,14 @@ mw_stop()
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
for i in $PLIST
do
kill -9 $i
kill -9 $i > /dev/null 2>&1
done
pids=`ps -ef|grep task.py | grep -v grep |awk '{print $2}'`
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p
kill -9 $p > /dev/null 2>&1
done
}
+20 -17
View File
@@ -16,6 +16,7 @@ cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
| CentOS 9 Stream |✅ |✅ |
| Debian 10.3 |✅ |✅ |
| Debian 11.3 |✅ |✅ |
| Debian 12.0 |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |
@@ -28,23 +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 |
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| 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 |
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
| 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 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
@@ -56,6 +58,7 @@ cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
| CentOS 9 Stream |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |
| Debian 12 |✅ |✅ |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |
+1
View File
@@ -0,0 +1 @@
存放VIP关键数据
+8 -5
View File
@@ -194,14 +194,17 @@ def backupAllFunc(stype):
'/scripts/backup.py ' + args
os.system(cmd)
# 开始执行上传信息
bk_prefix = prefix_dict[stype]
bk_name = stype
# 开始执行上传信息.
if stype.find('database_') > -1:
bk_name = 'database'
plugin_name = stype.replace('database_', '')
bk_prefix = plugin_name + '/db'
stype = 'database'
else:
bk_prefix = prefix_dict[stype]
bk_name = stype
find_path = mw.getBackupDir() + '/' + bk_name + '/' + bk_prefix + '_' + name
find_new_file = "ls " + find_path + \
@@ -212,10 +215,10 @@ def backupAllFunc(stype):
mw.echoInfo("not find upload file!")
return False
print("|-准备上传文件 {}".format(filename))
ftp = FtpPSClient()
ftp.uploadFile(filename, stype)
return True
return ''
def backupSite():
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+57
View File
@@ -0,0 +1,57 @@
<style type="text/css">
.docker-sub {
border-bottom: 1px solid #ccc;
height: 30px;
line-height: 30px;
margin-bottom: 15px;
}
.docker-sub .on {
border-bottom: 2px solid #20a53a;
color: #20a53a;
font-weight: bold;
font-family: "宋体";
}
.docker-sub span {
display: inline-block;
font-size: 14px;
height: 30px;
padding: 0 25px;
cursor: pointer;
}
.docker-environments {
resize: none;
width: 330px;
height: 80px;
line-height: 20px;
padding: 5px 8px;
border: 1px solid #ddd;
font-size: 12px;
}
</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('docker');">服务</p>
<p onclick="pluginInitD('docker');">自启动</p>
<p onclick="dockerConList();">容器列表</p>
<p onclick="dockerImageList();">镜像列表</p>
<p onclick="dockerIpList();">IP地址池</p>
<p onclick="repoList();">仓库</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinWidth(800);
resetPluginWinHeight(400);
$.getScript( "/plugins/file?name=docker&f=js/docker.js", function(){
pluginService('docker', $('.plugin_version').attr('version'));
});
</script>
+725
View File
@@ -0,0 +1,725 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
import docker
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getDClient():
try:
client = docker.from_env()
except Exception as e:
client = docker.DockerClient(
base_url='unix:///Users/midoks/.docker/run/docker.sock')
return client
def getPluginName():
return 'docker'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConf():
path = getServerDir() + "/redis.conf"
return path
def getConfTpl():
path = getPluginDir() + "/config/redis.conf"
return path
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
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(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(self, data, ck=[]):
for i in range(len(ck)):
print(data[i])
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
data = mw.execShell(
"ps -ef|grep docker |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def initDreplace():
return ''
def dockerOp(method):
file = initDreplace()
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' docker')
if data[1] == '':
return 'ok'
return data[1]
return 'fail'
def start():
return dockerOp('start')
def stop():
return dockerOp('stop')
def restart():
status = dockerOp('restart')
log_file = runLog()
mw.execShell("echo '' > " + log_file)
return status
def reload():
return dockerOp('reload')
def initdStatus():
if mw.isAppleSystem():
return "Apple Computer does not support"
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
# UTC时间转换为时间戳
def utc_to_local(utc_time_str, utc_format='%Y-%m-%dT%H:%M:%S'):
import pytz
import datetime
import time
local_tz = pytz.timezone('Asia/Chongqing')
local_format = "%Y-%m-%d %H:%M"
utc_dt = datetime.datetime.strptime(utc_time_str, utc_format)
local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
time_str = local_dt.strftime(local_format)
return int(time.mktime(time.strptime(time_str, local_format)))
def conList():
c = getDClient()
clist = c.containers.list(all=True)
conList = []
for con in clist:
tmp = con.attrs
tmp['Created'] = utc_to_local(tmp['Created'].split('.')[0])
conList.append(tmp)
return conList
def conListData():
try:
clist = conList()
except Exception as e:
return mw.returnJson(False, '未开启Docker')
return mw.returnJson(True, 'ok', clist)
def dockerRemoveCon():
args = getArgs()
data = checkArgs(args, ['Hostname'])
if not data[0]:
return data[1]
Hostname = args['Hostname']
c = getDClient()
try:
conFind = c.containers.get(Hostname)
try:
path_list = conFind.attrs['GraphDriver'][
'Data']['LowerDir'].split(':')
for i in path_list:
mw.execShell('chattr -R -i %s' % i)
except:
pass
conFind.remove(force=True)
return mw.returnJson(True, '成功删除!')
except docker.errors.APIError as ex:
return mw.returnJson(False, '删除失败!' + str(ex))
def dockerLogCon():
args = getArgs()
data = checkArgs(args, ['Hostname'])
if not data[0]:
return data[1]
Hostname = args['Hostname']
c = getDClient()
try:
conFind = c.containers.get(Hostname)
if not conFind:
return mw.returnJson(False, 'The specified container does not exist!')
log = conFind.logs()
if not isinstance(log, str):
log = log.decode()
return mw.returnJson(True, log)
except docker.errors.APIError as ex:
return mw.returnJson(False, 'Get Logs failed')
def dockerRunCon():
# 启动容器
args = getArgs()
data = checkArgs(args, ['Hostname'])
if not data[0]:
return data[1]
Hostname = args['Hostname']
c = getDClient()
try:
conFind = c.containers.get(Hostname)
if not conFind:
return mw.returnJson(False, 'The specified container does not exist!')
conFind.start()
return mw.returnJson(True, '启动成功!')
except docker.errors.APIError as ex:
return mw.returnJson(False, '启动失败!' + str(ex))
def dockerStopCon():
# 停止容器
args = getArgs()
data = checkArgs(args, ['Hostname'])
if not data[0]:
return data[1]
Hostname = args['Hostname']
c = getDClient()
try:
conFind = c.containers.get(Hostname)
if not conFind:
return mw.returnJson(False, 'The specified container does not exist!')
conFind.stop()
return mw.returnJson(True, '停止成功!')
except docker.errors.APIError as ex:
return mw.returnJson(False, '停止失败!' + str(ex))
def dockerExec():
# 容器执行命令
args = getArgs()
data = checkArgs(args, ['Hostname'])
if not data[0]:
return data[1]
Hostname = args['Hostname']
debug_path = 'data/debug.pl'
if os.path.exists(debug_path):
return mw.returnJson(False, '开发模式不能进入!')
c = getDClient()
try:
conFind = c.containers.get(Hostname)
cmd = 'docker container exec -it %s /bin/sh' % Hostname
return mw.returnJson(True, cmd)
except docker.errors.APIError as ex:
return mw.returnJson(False, '连接失败!')
def imageList():
imageList = []
c = getDClient()
ilist = c.images.list()
for image in ilist:
tmp_attrs = image.attrs
if len(tmp_attrs['RepoTags']) == 1:
tmp_image = {}
tmp_image['Id'] = tmp_attrs['Id'].split(':')[1][:12]
tmp_image['RepoTags'] = tmp_attrs['RepoTags'][0]
tmp_image['Size'] = tmp_attrs['Size']
tmp_image['Labels'] = tmp_attrs['Config']['Labels']
tmp_image['Comment'] = tmp_attrs['Comment']
tmp_image['Created'] = utc_to_local(
tmp_attrs['Created'].split('.')[0])
imageList.append(tmp_image)
else:
for i in range(len(tmp_attrs['RepoTags'])):
tmp_image = {}
tmp_image['Id'] = tmp_attrs['Id'].split(':')[1][:12]
tmp_image['RepoTags'] = tmp_attrs['RepoTags'][i]
tmp_image['Size'] = tmp_attrs['Size']
tmp_image['Labels'] = tmp_attrs['Config']['Labels']
tmp_image['Comment'] = tmp_attrs['Comment']
tmp_image['Created'] = utc_to_local(
tmp_attrs['Created'].split('.')[0])
imageList.append(tmp_image)
imageList = sorted(imageList, key=lambda x: x['Created'], reverse=True)
return imageList
def dockerPull():
# pull Dockr 官方镜像
args = getArgs()
data = checkArgs(args, ['images'])
if not data[0]:
return data[1]
images = args['images']
if ':' in images:
pass
else:
images = images + ':latest'
c = getDClient()
try:
ret = c.images.pull(images)
if ret:
return mw.returnJson(True, '拉取成功!')
else:
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
except:
ret = mw.execShell('docker image pull %s' % images)
if 'invalid' in ret[-1]:
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
else:
return mw.returnJson(True, '拉取成功!')
def dockerPlulPath(path):
if not path and path == '':
return mw.returnJson(False, 'Invalid address')
ret = mw.execShell('docker image pull %s' % path)
if 'invalid' in ret[-1]:
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
else:
return mw.returnJson(True, '拉取成功!')
def dockerPullReg():
# pull Dockr 官方镜像
args = getArgs()
data = checkArgs(args, ['path'])
if not data[0]:
return data[1]
path = args['path']
return dockerPlulPath(path)
# 判断镜像是否存在
def checkImage(path):
image_list = imageList()
for i in image_list:
if path == i["RepoTags"]:
return mw.returnData(False, '镜像已存在!')
def dockerPullPrivateNew():
# pull Dockr 官方镜像
args = getArgs()
data = checkArgs(args, ['path'])
if not data[0]:
return data[1]
path = args['path']
check = checkImage(path)
if check:
return mw.getJson(check)
my_repo = repoList()
if not my_repo:
return mw.returnJson(False, '未登录任何私人存储库,请登录然后拉取')
return dockerPlulPath(path)
def imageListData():
try:
ilist = imageList()
except Exception as e:
return mw.returnJson(False, '未开启Docker')
return mw.returnJson(True, 'ok', ilist)
def dockerRemoveImage():
args = getArgs()
data = checkArgs(args, ['imageId', 'repoTags'])
if not data[0]:
return data[1]
repoTags = args['repoTags']
imageId = args['imageId']
c = getDClient()
try:
c.images.remove(repoTags)
return mw.returnJson(True, '成功删除')
except:
try:
c.images.remove(imageId)
return mw.returnJson(True, '成功删除!')
except docker.errors.APIError as ex:
return mw.returnJson(False, '删除失败, 当前镜像正在使用!')
def dockerLoginCheck(user_name, user_pass, registry):
# 登陆验证
cmd = 'docker login -u=%s -p %s %s' % (user_name, user_pass, registry)
# print(cmd)
login_test = mw.execShell(cmd)
# print(login_test)
ret = 'required$|Error'
ret2 = re.findall(ret, login_test[-1])
if len(ret2) == 0:
return True
else:
return False
def getDockerIpListData():
# 取IP列表
path = getServerDir()
ipConf = path + '/iplist.json'
if not os.path.exists(ipConf):
return []
iplist = json.loads(mw.readFile(ipConf))
return iplist
def getDockerIpList():
data = getDockerIpListData()
return mw.returnJson(True, 'ok!', data)
def dockerAddIP():
# 添加IP
args = getArgs()
data = checkArgs(args, ['address', 'netmask', 'gateway'])
if not data[0]:
return data[1]
path = getServerDir()
ipConf = path + '/iplist.json'
if not os.path.exists(ipConf):
iplist = []
mw.writeFile(ipConf, json.dumps(iplist))
iplist = json.loads(mw.readFile(ipConf))
ipInfo = {
'address': args['address'],
'netmask': args['netmask'],
'gateway': args['gateway'],
}
iplist.append(ipInfo)
mw.writeFile(ipConf, json.dumps(iplist))
return mw.returnJson(True, '添加成功!')
def dockerDelIP():
# 删除IP
args = getArgs()
data = checkArgs(args, ['address'])
if not data[0]:
return data[1]
path = getServerDir()
ipConf = path + '/iplist.json'
if not os.path.exists(ipConf):
return mw.returnJson(False, '指定的IP不存在。!')
iplist = json.loads(mw.readFile(ipConf))
newList = []
for ipInfo in iplist:
if ipInfo['address'] == args['address']:
continue
newList.append(ipInfo)
mw.writeFile(ipConf, json.dumps(newList))
return mw.returnJson(True, '成功删除!')
def getDockerCreateInfo():
# 取创建依赖
import psutil
data = {}
data['images'] = imageList()
data['memSize'] = int(psutil.virtual_memory().total / 1024 / 1024)
data['iplist'] = getDockerIpListData()
return mw.returnJson(True, 'ok!', data)
def __release_port(port):
from collections import namedtuple
try:
import firewall_api
firewall_api.firewall_api().addAcceptPortArgs(port, 'docker', 'port')
return port
except Exception as e:
return "Release failed {}".format(e)
def dockerCreateCon():
args = getArgs()
data = checkArgs(args, ['environments', 'command',
'entrypoint', 'image', 'mem_limit', 'ports', 'volumes'])
if not data[0]:
return data[1]
environments = args['environments']
environments = environments.strip().split()
command = args['command']
entrypoint = args['entrypoint']
image = args['image']
mem_limit = args['mem_limit']
ports = args['ports']
ports = ports.replace('[', '(').replace(']', ')')
volumes = args['volumes']
# if __name__ == "__main__":
# print(args)
try:
c = getDClient()
conObject = c.containers.run(
image=image,
mem_limit=mem_limit + 'M',
ports=eval(ports),
auto_remove=False,
command=command,
detach=True,
stdin_open=True,
tty=True,
entrypoint=entrypoint,
privileged=True,
volumes=json.loads(volumes),
cpu_shares=10,
environment=environments
)
if conObject:
__release_port(ports)
return mw.returnJson(True, '创建成功!')
return mw.returnJson(False, '创建失败!')
except docker.errors.APIError as ex:
return mw.returnJson(False, '创建失败!' + str(ex))
def dockerLogin():
args = getArgs()
# print(args)
data = checkArgs(args, ['user', 'passwd', 'hub_name',
'namespace', 'registry', 'repository_name'])
if not data[0]:
return data[1]
user_name = args['user']
user_pass = args['passwd']
registry = args['registry']
hub_name = args['hub_name']
namespace = args['namespace']
repository_name = args['repository_name']
ret_status = dockerLoginCheck(user_name, user_pass, registry)
path = getServerDir()
if ret_status:
user_file = path + '/user.json'
user_info = mw.readFile(user_file)
if not user_info:
user_info = []
else:
user_info = json.loads(user_info)
ret = {}
ret['user_name'] = user_name
ret['user_pass'] = user_pass
ret['registry'] = registry
ret['hub_name'] = hub_name
ret['namespace'] = namespace
ret['repository_name'] = repository_name
if not registry:
ret['registry'] = "docker.io"
user_info.append(ret)
mw.writeFile(user_file, json.dumps(user_info))
return mw.returnJson(True, '成功登录!')
return mw.returnJson(False, '登录失败!')
# 删除用户信息
def delete_user_info(registry):
path = getServerDir()
user_file = path + '/user.json'
user_info = mw.readFile(user_file)
if user_info:
user_info = json.loads(user_info)
for i in range(len(user_info)):
if registry in user_info[i].values():
del(user_info[i])
mw.writeFile(user_file, json.dumps(user_info))
return True
def dockerLogout():
args = getArgs()
data = checkArgs(args, ['registry'])
if not data[0]:
return data[1]
registry = args['registry']
if registry == "docker.io":
registry = ""
login_test = mw.execShell('docker logout %s' % registry)
if registry == "":
registry = "docker.io"
ret = 'required$|Error'
ret2 = re.findall(ret, login_test[-1])
delete_user_info(registry)
if len(ret2) == 0:
return mw.returnJson(True, '退出成功')
else:
return mw.returnJson(True, '退出失败')
def repoList():
path = getServerDir()
repostory_info = []
user_file = path + '/user.json'
if os.path.exists(user_file):
user_info = mw.readFile(user_file)
user_info = json.loads(user_info)
for i in user_info:
tmp = {}
tmp["hub_name"] = i["hub_name"]
tmp["registry"] = i["registry"]
tmp["namespace"] = i["namespace"]
tmp['repository_name'] = i["repository_name"]
repostory_info.append(tmp)
return mw.returnJson(True, 'ok', repostory_info)
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())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'conf':
print(getConf())
elif func == 'con_list':
print(conListData())
elif func == 'docker_con_log':
print(dockerLogCon())
elif func == 'docker_remove_con':
print(dockerRemoveCon())
elif func == 'docker_run_con':
print(dockerRunCon())
elif func == 'docker_stop_con':
print(dockerStopCon())
elif func == 'docker_exec':
print(dockerExec())
elif func == 'docker_pull':
print(dockerPull())
elif func == 'docker_pull_reg':
print(dockerPullReg())
elif func == 'image_list':
print(imageListData())
elif func == 'docker_get_iplist':
print(getDockerIpList())
elif func == 'docker_del_ip':
print(dockerDelIP())
elif func == 'docker_add_ip':
print(dockerAddIP())
elif func == 'get_docker_create_info':
print(getDockerCreateInfo())
elif func == 'docker_create_con':
print(dockerCreateCon())
elif func == 'docker_remove_image':
print(dockerRemoveImage())
elif func == 'docker_login':
print(dockerLogin())
elif func == 'docker_logout':
print(dockerLogout())
elif func == 'repo_list':
print(repoList())
else:
print('error')
+19
View File
@@ -0,0 +1,19 @@
{
"sort": 7,
"ps": "Docker 是一个开源的应用容器引擎(开发测试中)",
"name": "docker",
"title": "Docker",
"shell": "install.sh",
"versions":["1.0"],
"updates":["1.0"],
"tip": "soft",
"checks": "server/docker",
"path": "server/docker",
"display": 1,
"author": "Zend",
"date": "2017-04-01",
"home": "https://docker.io",
"doc1":"https://docker-py.readthedocs.io/",
"type": 0,
"pid": "2"
}
+84
View File
@@ -0,0 +1,84 @@
#!/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")
# cd /www/server/mdserver-web/plugins/docker && /bin/bash install.sh uninstall 1.0
# cd /www/server/mdserver-web/plugins/docker && /bin/bash install.sh install 1.0
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
Install_Docker()
{
# which docker
# if [ "$?" == "0" ];then
# echo '安装已经完成docker' > $install_tmp
# exit 0
# fi
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source
if [ ! -d $serverPath/docker ];then
curl -fsSL https://get.docker.com | bash
mkdir -p $serverPath/docker
fi
pip install docker
pip install pytz
if [ -d $serverPath/docker ];then
echo "${VERSION}" > $serverPath/docker/version.pl
echo '安装完成' > $install_tmp
cd ${rootPath} && python3 ${rootPath}/plugins/docker/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/docker/index.py initd_install
fi
}
Uninstall_Docker()
{
CMD=yum
which apt
if [ "$?" == "0" ];then
CMD=apt
fi
if [ -f /usr/lib/systemd/system/docker.service ];then
systemctl stop docker
systemctl disable docker
rm -rf /usr/lib/systemd/system/docker.service
systemctl daemon-reload
fi
$CMD remove -y docker docker-ce-cli containerd.io
# docker-client \
# docker-client-latest \
# docker-common \
# docker-latest \
# docker-latest-logrotate \
# docker-logrotate \
# docker-selinux \
# docker-engine-selinux \
# docker-engine \
# docker-ce
rm -rf $serverPath/docker
echo "Uninstall_Docker" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_Docker
else
Uninstall_Docker
fi
+864
View File
@@ -0,0 +1,864 @@
function dPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'docker';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function dPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'docker';
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
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 logsCon(id){
dPost('docker_con_log','',{Hostname:id},function(rdata){
var rdata = $.parseJSON(rdata.data);
if(!rdata.status) {
layer.msg(rdata.msg,{icon:2});
return;
};
layer.open({
type:1,
title:'Docker日志',
area: '600px',
closeBtn: 2,
content:'<div class="bt-form">'
+'<pre class="crontab-log" style="overflow: auto; \
border: 0px none; line-height:23px;padding: 15px; \
margin: 0px; white-space: pre-wrap; height: 405px; \
background-color: rgb(51,51,51);color:#f1f1f1;\
border-radius:0px;">'+ (rdata.msg == '' ? 'No logs':rdata.msg) +'</pre>'
+'</div>',
success:function(index,layers){
$(".crontab-log").scrollTop(1000000);
}
});
});
}
function deleteCon(Hostname){
// 删除容器
safeMessage('删除容器 ', '删除容器 ['+Hostname+'], 确定?',function(){
dPost('docker_remove_con','',{Hostname:Hostname},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
dockerConListRender();
}
},{icon:rdata.status?1:2});
});
});
}
function startCon(Hostname){
dPost('docker_run_con','',{Hostname:Hostname},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
dockerConListRender();
}
},{icon:rdata.status?1:2});
});
}
function stopCon(Hostname){
dPost('docker_stop_con','',{Hostname:Hostname},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
dockerConListRender();
}
},{icon:rdata.status?1:2});
});
}
function execCon(Hostname){
webShell();
var pdata_socket = {};
var shell = setInterval(function(){
if($('.term-box').length == 0){
pdata_socket['data'] = 'exit\n';
socket.emit('webssh',pdata_socket);
setTimeout(function(){socket.emit('webssh',pdata_socket['data']);},1000);
clearInterval(shell);
}
},500);
setTimeout(function(){
dPost('docker_exec','',{Hostname:Hostname},function(res){
var res = $.parseJSON(res.data);
if(!res.status){
layer.msg(res.msg,{icon:res.status?1:2});
}else{
pdata_socket['data'] = 'clear && ' + res.msg +'\n'
socket.emit('webssh',pdata_socket);
setTimeout(function(){socket.emit('webssh',pdata_socket['data']);},1000);
}
});
});
}
function dockerConListRender(){
dPost('con_list', '', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
console.log(rdata);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,time:2000});
return;
}
var list = '';
var rlist = rdata.data;
for (var i = 0; i < rlist.length; i++) {
var docker_status = 'stop';
var status = '<span class="glyphicon glyphicon-pause" style="color:red;font-size:12px"></span>';
if (rlist[i]['State']['Status'] == 'running'){
docker_status = 'start';
status = '<span class="glyphicon glyphicon-play" style="color:#20a53a;font-size:12px"></span>';
}
var op = '';
op += '<a href="javascript:;" onclick="execCon(\''+rlist[i]['Config']['Hostname']+'\')" class="btlink">终端</a> | ';
op += '<a href="javascript:;" onclick="logsCon(\''+rlist[i]['Id']+'\')" class="btlink">日志</a> | ';
op += '<a href="javascript:;" onclick="deleteCon(\''+rlist[i]['Config']['Hostname']+'\')" class="btlink">删除</a>';
list += '<tr>';
list += '<td>'+rlist[i]['Name'].substring(1)+'</td>';
list += '<td>'+rlist[i]['Config']['Image']+'</td>';
list += '<td>'+getFormatTime(rlist[i]['Created'])+'</td>';
if (docker_status == 'start'){
list += '<td style="cursor:pointer;" align="center" onclick="stopCon(\''+rlist[i]['Config']['Hostname']+'\')">'+status+'</td>';
} else{
list += '<td style="cursor:pointer;" align="center" onclick="startCon(\''+rlist[i]['Config']['Hostname']+'\')">'+status+'</td>';
}
list += '<td class="text-right">'+op+'</td>';
list += '</tr>';
}
$('#con_list tbody').html(list);
});
}
function createConTemplate(){
dPost('get_docker_create_info','',{},function(rdata){
var rdata = $.parseJSON(rdata.data);
console.log(rdata);
var rdata = rdata.data;
var imageOpt = '';
for(var i=0;i<rdata.images.length;i++){
var imageName = rdata.images[i].RepoTags.indexOf('panel') == -1? rdata.images[i].RepoTags:'aaPanel:'+rdata.images[i].RepoTags.split(':')[1];
imageOpt += '<option value="'+rdata.images[i].RepoTags+'">'+imageName+'</option>';
}
var iplistOpt = '';
for(var i=0;i<rdata.iplist.length;i++){
iplistOpt += '<option value="'+rdata.iplist[i].address+'">'+rdata.iplist[i].address+'</option>';
}
var layer_index = layer.open({
type: 1,
title: "创建容器",
area: '556',
closeBtn: 2,
shadeClose: false,
btn: ['确定', '取消'],
content: '<div class="bt-form pd20 pb70 ceart-docker new_tname">\
<div class="line">\
<span class="tname">镜像</span>\
<div class="info-r c4"><select class="bt-input-text docker-image" style="width:330px">'+imageOpt+'</select></div>\
</div>\
<div class="line">\
<span class="tname">绑定IP</span>\
<div class="info-r c4"><select class="bt-input-text docker-address" style="width:330px"><option value="0.0.0.0">0.0.0.0</optin>'+iplistOpt+'</select></div>\
</div>\
<div class="line">\
<span class="tname">端口映射</span>\
<div class="info-r c4">\
<div class="type-port">\
<input class="bt-input-text" name="name1" type="number" placeholder="容器端口" style="width:110px;margin-right:15px">\
<select class="bt-input-text" style="width:90px;margin-right:15px"><option value="TCP">TCP</optin><option value="UDP">UDP</optin></select>\
<input class="bt-input-text" name="name2" type="number" placeholder="服务器端口" style="width:90px">\
<span class="plus glyphicon glyphicon-plus" style="color: #20a53a;font-size: 11px;"></span>\
</div>\
<div class="divtable" style="max-height:100px;overflow:auto; margin-top:15px;width:330px;padding-left: 0px;">\
<table class="table table-hover">\
<tbody id="portabletr"><tr class="more1"><td>当前未添加端口映射</td></tr></tbody>\
</table>\
</div>\
</div>\
</div>\
<div class="line">\
<span class="tname">目录映射</span>\
<div class="info-r c4">\
<div class="type-volumes">\
<input class="bt-input-text" name="path1" type="text" placeholder="容器目录" style="width:110px;margin-right:15px">\
<select class="bt-input-text" style="width:90px;margin-right:15px"><option value="rw">read-write</optin><option value="ro">read only</optin></select>\
<input class="bt-input-text" name="path2" type="text" placeholder="服务器目录" style="width:90px">\
<span class="plus2 glyphicon glyphicon-plus" style="color: #20a53a;font-size: 11px;"></span>\
</div>\
<div class="divtable" style="max-height:100px;overflow:auto; margin-top:15px;width:330px;padding-left: 0px;">\
<table class="table table-hover">\
<tbody id="portabletr2"><tr class="more2"><td>当前未添加目录映射</td></tr></tbody>\
</table>\
</div>\
</div>\
</div>\
<div class="line">\
<span class="tname" style="height: auto;line-height: 20px;">环境变量<br>(每行一个)</span>\
<div class="info-r c4" style="margin-bottom: 0;">\
<div class="type-volumes">\
<textarea placeholder="Add variables format as following, one per line:\nJAVA_HOME=/usr/local/java8&#10;HOSTNAME=master" name="environments" class="docker-environments"></textarea>\
</div>\
</div>\
</div>\
<div class="line">\
<span class="tname">内存配额</span>\
<div class="info-r c4"><input class="bt-input-text mr5 docker-mem" type="number" style="width:100px" value="'+parseInt(rdata.memSize/2)+'">\
<span class="dc-un">MB</span><i class="help">不超过, '+ rdata.memSize +'MB</i></div>\
</div>\
<div class="line">\
<span class="tname">CPU配额</span>\
<div class="info-r c4">\
<input class="bt-input-text mr5 docker-cpu" type="number" max="100" min="1" style="width:100px" value="100">\
<span class="dc-un"></span><i class="help">越大,占用的CPU越多</i></div>\
</div>\
<div class="line">\
<span class="tname">执行命令</span>\
<div class="info-r c4"><input class="bt-input-text docker-command" type="text" style="width:330px" value="" placeholder="/bin/bash"></div>\
</div>\
<div class="line" style="display:none">\
<span class="tname">entrypoint</span>\
<div class="info-r c4"><input class="bt-input-text docker-entrypoint" type="text" style="width:300px" value=""></div>\
</div>\
</div>',
success:function(){
$(".bt-cancel").click(function(){
layer.close(layer_index);
});
$(".plus").click(function(){
var name1 = $(".type-port input[name='name1']").val();
var name2 = $(".type-port input[name='name2']").val();
if(name1 < 1 || name1 > 65535 || name2 < 1 || name2 > 65535 || isNaN(name1) || isNaN(name2)){
layer.msg('Port setting value range is invalid, range [1-65535]',{icon:2});
return;
}
var portval = $('#portabletr')[0].childNodes;
for(var i=0;i<portval.length;i++){
if(portval[i].childNodes[0].innerText == '当前未添加目录映射') continue;
var sport = portval[i].childNodes[2].innerText;
if(name2 == sport){
layer.msg('The port ['+name2+'] is already in the mapping list!',{icon:2});
return;
}
}
var address = $('.docker-address').val();
if(address == '0.0.0.0'){
address = '*';
}
var port = address + ':' + name2;
var loadT = layer.msg('Testing <img src="/static/img/ing.gif">',{icon:16,time:0,shade: [0.3, "#000"]});
$.post('/plugin?action=a&name=docker&s=IsPortExists',{port:port},function(rdata){
layer.close(loadT);
if(rdata !== false){
layer.msg('Port ['+name2+'] is already in the mapping list!',{icon:2});
return;
}
var selecttype = $(".type-port select").val();
var portable= '<tr><td>'+name1+'</td><td>'+selecttype+'</td><td>'+name2+'</td><td class="text-right" width="60"><a href="javascript:;" class="btlink minus">Del</a></td></tr>';
$("#portabletr").append(portable);
$(".more1").remove();
$(".minus").click(function(){
$(this).parents("tr").remove();
});
});
});
$(".plus2").click(function(){
var path1 = $(".type-volumes input[name='path1']").val();
var path2 = $(".type-volumes input[name='path2']").val();
var notPath = ['/boot','/bin','/sbin','/etc','/usr/bin','/usr/sbin','/dev']
if($.inArray(path2,notPath) != -1){
layer.msg('Cannot map' + path2,{icon:2});
return;
}
var portval = $('#portabletr2')[0].childNodes;
for(var i=0;i<portval.length;i++){
if(portval[i].childNodes[0].innerText == '当前未添加目录映射') continue;
var sport = portval[i].childNodes[2].innerText;
if(path2 == sport){
layer.msg('Directory ['+path2+'] is already in the mapping list!',{icon:2});
return;
}
}
var selecttype = $(".type-volumes select").val();
var portable= '<tr>\
<td class="td_width_1" title="'+path1+'">'+path1+'</td>\
<td>'+selecttype+'</td><td title="'+path2+'" class="td_width_1" style="max-width: 138px;">'+path2+'</td>\
<td class="text-right" width="50"><a href="javascript:;" class="btlink minus2">Del</a></td>\
</tr>';
$("#portabletr2").append(portable);
$(".more2").remove();
$(".minus2").click(function(){
$(this).parents("tr").remove();
});
});
},
yes:function(layero,layer_id){
var ports = {};
var volumes = {};
var portval = $('#portabletr')[0].childNodes;
var address = $('.docker-address').val();
var portval2 = $('#portabletr2')[0].childNodes;
var command = $('.docker-command').val()
var entrypoint = $('.docker-entrypoint').val()
var accept = [];
//遍历端口映射
for(var i=0;i<portval.length;i++){
// console.log(portval[i].childNodes[0].innerText);
if(portval[i].childNodes[0].innerText == '当前未添加端口映射') {
continue;
}
var port = portval[i].childNodes[0].innerText.replace(/\s/g,'');
var dport = port + '/' + portval[i].childNodes[1].innerText.toLowerCase().replace(/\s/g,'');
var sport = [address,parseInt(portval[i].childNodes[2].innerText.replace(/\s/g,''))];
ports[dport] = sport
accept.push(port);
}
//遍历目录映射
volumes['/sys/fs/cgroup'] = {'bind':'/sys/fs/cgroup', 'mode': 'rw'};
for(var i=0;i<portval2.length;i++){
if(portval2[i].childNodes[0].innerText.replace(/\s/g,' ') == '当前未添加目录映射') {
continue;
}
var dpath = portval2[i].childNodes[2].innerText.replace(/\s/g,'');
var spath = {'bind':portval2[i].childNodes[0].innerText.replace(/\s/g,''),'mode':portval2[i].childNodes[1].innerText.toLowerCase().replace(/\s/g,'')};
volumes[dpath] = spath
}
var data = {
image:$('.docker-image').val(),
ports:JSON.stringify(ports),
accept:JSON.stringify(accept),
volumes:JSON.stringify(volumes),
environments:$('.docker-environments').val(),
mem_limit:$('.docker-mem').val(),
cpu_shares:$('.docker-cpu').val(),
command:command,
entrypoint:entrypoint
}
if(data.mem_limit > rdata.memSize){
layer.msg('内存配额不能大于物理内存 ['+rdata.memSize+']!',{icon:2});
return;
}
if(data.cpu_shares > 100 || data.cpu_shares < 1){
layer.msg('CPU配额设置值范围应为 [1-100]!',{icon:2});
return;
}
dPost('docker_create_con','', data, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
layer.close(layer_index);
dockerConListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
}
});
});
}
function dockerConList(){
var con = '<div class="safe bgw">\
<button onclick="createConTemplate();" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">创建容器</button>\
<div class="divtable mtb10">\
<div class="tablescroll">\
<table id="con_list" 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>状态</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody></tbody></table>\
</div>\
</div>\
</div>';
$(".soft-man-con").html(con);
dockerConListRender();
}
function deleteImages(tag, id){
safeMessage('删除镜像','删除镜像['+tag+'],确定?',function(){
dPost('docker_remove_image','', {imageId:id,repoTags:tag},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
dockerImageListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
});
}
function pullImages(tag, id){
console.log(tag, id);
layer.msg('开发中!',{ icon: 2 });
}
function dockerImageListRender(){
dPost('image_list', '', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log(rdata);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,time:2000});
return;
}
var list = '';
var rlist = rdata.data;
for (var i = 0; i < rlist.length; i++) {
var tag = rlist[i]['RepoTags'].split(":")[1];
var license = 'null';
var desc = 'null';
if (rlist[i]['Labels'] == null){
license = 'free';
}
var op = '';
op += '<a href="javascript:;" onclick="pullImages(\''+rlist[i]['RepoTags']+'\',\''+rlist[i]['Id']+'\')" class="btlink">拉取</a> | ';
op += '<a href="javascript:;" onclick="deleteImages(\''+rlist[i]['RepoTags']+'\',\''+rlist[i]['Id']+'\')" class="btlink">删除</a>';
list += '<tr>';
list += '<td>'+rlist[i]['RepoTags']+'</td>';
list += '<td>'+tag+'</td>';
list += '<td>'+toSize(rlist[i]['Size'])+'</td>';
list += '<td>'+license+'</td>';
list += '<td>'+desc+'</td>';
list += '<td class="text-right">'+op+'</td>';
list += '</tr>';
}
$('#con_list tbody').html(list);
});
}
function dockerPullImagesFileTemplate(){
// 拉取镜像文件模板
var layer_index = layer.open({
type: 1,
title: "获取镜像",
area: '500px',
closeBtn: 2,
shadeClose: false,
content: '<div class="bt-docker pd20">'+
'<div class="docker-sub">'+
'<span class="on">官方库</span>'+
'<span>公共库</span>'+
'<span>私有库</span>'+
'</div>'+
'<div class="bt-form bt-docker-con">'+
'<div class="conter official_pull pd15"><div class="line">'+
'<span class="tname">镜像名:</span>\
<div class="info-r c4">\
<input class="bt-input-text mr5" type="text" name="official_pull_name" style="width:218px" value="">\
<button type="button" class="btn btn-sm btn-success official_pull_btn">获取</button>\
</div>'+
'</div></div>'+
'<div class="conter public_pull pd15" style="display: none;"><div class="line">'+
'<span class="tname">镜像名:</span>\
<div class="info-r c4">\
<input class="bt-input-text mr5" type="text" name="public_pull_path" style="width:218px" value="">\
<button type="button" class="btn btn-sm btn-success public_pull_btn">获取</button>\
</div>'+
'</div></div>'+
'<div class="conter private_pull pd15" style="display: none;">'+
'<div class="line"><span class="tname">镜像地址:</span>\
<div class="info-r c4">\
<input class="bt-input-text mr5" type="text" name="private_pull_path" style="width:218px" value="">\
<button type="button" class="btn btn-sm btn-success private_pull_btn">获取</button>\
</div>\
</div>\
</div>\
</div>\
</div>',
success:function(layero,layer_id){
$('.docker-sub span').click(function(){
var index = $(this).index();
$(this).addClass('on').siblings().removeClass('on');
$(this).parent().next().find('.conter').eq(index).show().siblings().hide();
});
$('.official_pull_btn').click(function(){
var name = $('[name="official_pull_name"]').val();
if(name == ''){
layer.msg('镜像名不能为空!');
return;
}
dPost('docker_pull','',{images:name}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
layer.close(layer_index);
dockerImageListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
});
$('.public_pull_btn').click(function(){
var path = $('[name="public_pull_path"]').val();
if(path == ''){
layer.msg('公共网络镜像地址不能为空。');
return;
}
dPost('docker_pull_reg','',{path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
layer.close(layer_index);
dockerImageListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
});
$('.private_pull_btn').click(function(){
var path = $('[name="private_pull_path"]').val();
if(path == ''){
layer.msg('专用镜像地址不能为空!');
return
}
dPost('docker_pull_private_new','',{path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
layer.close(layer_index);
dockerImageListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
});
}
});
}
function dockerImageList(){
var con = '<div class="safe bgw">\
<button onclick="dockerPullImagesFileTemplate()" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">获取镜像</button>\
<div class="divtable mtb10">\
<div class="tablescroll">\
<table id="con_list" 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>证书</th>\
<th>描述</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="databasePage" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
dockerImageListRender();
}
function deleteIpList(address){
safeMessage('删除IP','你将删除从IP地址池['+address+'],确定?',function(){
dPost('docker_del_ip','', {address:address},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if(rdata.status) {
dockerIpListRender();
}
},{ icon: rdata.status ? 1 : 2 });
});
});
}
function dockerIpListRender(){
dPost('docker_get_iplist', '', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log(rdata);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,time:2000});
return;
}
var list = '';
var rlist = rdata.data;
for (var i = 0; i < rlist.length; i++) {
var op = '';
op += '<a href="javascript:;" onclick="deleteIpList(\''+rlist[i]['address']+'\')" class="btlink">删除</a>';
list += '<tr>';
list += '<td>'+rlist[i]['address']+'</td>';
list += '<td>'+rlist[i]['netmask']+'</td>';
list += '<td>'+rlist[i]['gateway']+'</td>';
list += '<td class="text-right">'+op+'</td>';
list += '</tr>';
}
$('#ip_list tbody').html(list);
});
}
function dockerAddIpPool(){
var address = $('input[name="address"]').val();
var netmask = $('input[name="netmask"]').val();
var gateway = $('input[name="gateway"]').val();
dPost('docker_add_ip','', {address:address,netmask:netmask,gateway:gateway}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
dockerIpListRender();
},{icon:rdata.status?1:2})
});
}
function dockerIpList(){
var con = '<div class="safe bgw">\
<div class="search_input">\
<input class="bt-input-text mr5" type="text" style="width:150px" name="address" placeholder="IP地址">\
<input class="bt-input-text mr5" name="netmask" type="text" style="width:150px" placeholder="子网掩码">\
<input name="gateway" class="bt-input-text mr5" type="text" style="width:150px" placeholder="网关">\
<button class="btn btn-success btn-sm va0" onclick="dockerAddIpPool()">添加</button>\
</div>\
<div class="divtable mtb10">\
<div class="tablescroll">\
<table id="ip_list" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>IP地址</th>\
<th>子网掩码</th>\
<th>网关</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody></tbody></table>\
</div>\
<div id="databasePage" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
dockerIpListRender();
}
// login
function repoLogin(){
var _option1= "";
var obj = {hub_name: "", namespace: "",name: "", registry: "", user_pass: "", user_name: "",arry: ['Docker Repository','Other Repository']};
for(var i = 0; i< obj.arry.length;i++){
_option1 += '<option value="'+ obj.arry[i] +'">'+ obj.arry[i] +'</option>';
}
var layer_index = layer.open({
type: 1,
title: "登录到存储库",
area: '450px',
closeBtn: 2,
shadeClose: false,
content: '<div class="bt-docker-con docker_content">'+
'<style>.line .tname{width:120px;}</style>'+
'<div class="soft-man-con pd20 pb70 private_pull">'+
'<div class="line"><span class="tname">Repository Type</span><div class="info-r c4"><select class="bt-input-text mr5 project_version" name="dtype" style="width:250px">'+ _option1 +'</select></div></div>'+
'<div class="line"><span class="tname">Name:</span><div class="info-r"><input class="bt-input-text" type="text" name="ctm_name" style="width:250px" value="'+obj.name+'"></div></div>'+
'<div class="line"><span class="tname">Username:</span><div class="info-r"><input class="bt-input-text" type="text" name="user" style="width:250px" value="'+obj.user_name+'"></div></div>'+
'<div class="line"><span class="tname">Password:</span><div class="info-r"><input class="bt-input-text" type="password" name="passwd" style="width:250px" value="'+obj.user_pass+'"></div></div>'+
'<div class="line"><span class="tname">Repository Name:</span><div class="info-r"><input class="bt-input-text" type="text" name="hub_name" style="width:250px" value="'+obj.hub_name+'"></div></div>'+
'<div class="line"><span class="tname">Namespaces:</span><div class="info-r"><input class="bt-input-text" type="text" name="namespace" style="width:250px" value="'+obj.namespace+'"></div></div>'+
'<div class="line" style="display:none"><span class="tname">Registry:</span><div class="info-r"><input class="bt-input-text" type="text" name="registry" style="width:250px" value="'+obj.registry+'"></div></div>'+
'<div class="bt-form-submit-btn"><button type="button" class="btn btn-sm btn-success login_aliyun">登录</button></div>'+
'</div>'+
'</div>',
success:function(){
$('[name="dtype"]').change(function(e){
var docker_type = $(this).val();
if(docker_type == 'Other Repository'){
$('.docker_content .line').show();
}else{
$('.docker_content .line').filter(":lt(3)").show().end().filter(":gt(4)").hide();
}
});
$('.login_aliyun').click(function(){
var user = $('[name="user"]').val(),
passwd = $('[name="passwd"]').val(),
registry = $('[name="registry"]').val(),
name = $('[name="ctm_name"]').val(),
hub_name = $('[name="hub_name"]').val(),
namespace = $('[name="namespace"]').val();
var args = {
user:user,
passwd:passwd,
registry:'',
repository_name:name,
hub_name:hub_name,
namespace:namespace
};
if($('[name="dtype"]').val() == 'Docker Repository'){
args.registry = '';
}else{
args.registry = registry;
}
console.log(obj);
dPost('docker_login', '', args, function(rdata){
var rdata = $.parseJSON(rdata.data);
console.log(rdata);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
if(res.status){
repoListRender();
layer.close(layer_index);
}
});
});
}
});
}
function delRepo(address){
safeMessage('退出','你将退出 ['+address+'],确定?',function(){
dPost('docker_logout', '',
{registry:address},
function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
if(rdata.status) {
repoListRender();
}
}
);
});
}
function repoListRender(){
dPost('repo_list', '', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
console.log(rdata);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,time:2000});
return;
}
var list = '';
var rlist = rdata.data;
for (var i = 0; i < rlist.length; i++) {
list += '<tr>';
list += '<td>'+rlist[i]['hub_name']+'</td>';
list += '<td>'+rlist[i]['repository_name']+'</td>';
list += '<td>'+rlist[i]['namespace']+'</td>';
list += '<td>'+rlist[i]['registry']+'</td>';
list += '<td class="text-right"><a href="javascript:;" onclick="delRepo(\''+rlist[i]['registry']+'\')" class="btlink">删除</a></td>';
list += '</tr>';
}
$('#con_list tbody').html(list);
});
}
function repoList(){
var con = '<div class="safe bgw">\
<button id="docker_login" title="" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">登录</button>\
<div class="divtable mtb10">\
<div class="tablescroll">\
<table id="con_list" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>Name</th>\
<th>Repository Name</th>\
<th>NameSpace</th>\
<th>地址</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody>\
' + '</tbody></table>\
</div>\
<div id="databasePage" class="dataTables_paginate paging_bootstrap page"></div>\
</div>\
</div>';
$(".soft-man-con").html(con);
//login
$('#docker_login').click(function(){
repoLogin();
});
repoListRender();
}
+5 -1
View File
@@ -33,7 +33,11 @@ if [ ! -d $WEB_PATH ];then
mkdir -p $WEB_PATH
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
fi
fi
sysName=`uname`
+2 -2
View File
@@ -8,8 +8,8 @@
<p onclick="pluginConfig('gitea',null, 'conf');">配置文件</p>
<p onclick="gogsSetConfig();">配置修改</p>
<p onclick="giteaUserList();">用户列表</p>
<p onclick="pluginLogs('gitea',null,'run_log');">运行日志</p>
<p onclick="pluginLogs('gitea',null,'post_receive_log');" title="提交post-receive日志">提交日志</p>
<!-- <p onclick="pluginLogs('gitea',null,'run_log');">运行日志</p> -->
<!-- <p onclick="pluginLogs('gitea',null,'post_receive_log');" title="提交post-receive日志">提交日志</p> -->
<p onclick="giteaRead();">使用说明</p>
</div>
<div class="bt-w-con pd15">
+1 -1
View File
@@ -560,7 +560,7 @@ def userProjectList():
data['data'] = ret_data
data['args'] = args
data['list'] = mw.getPage(
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectList'})
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectListPost'})
return mw.returnJson(True, 'OK', data)
+2 -2
View File
@@ -1,8 +1,8 @@
{
"ps": "Gitea 是一个开源社区驱动的轻量级代码托管解决方案。",
"ps": "Gitea是一个开源社区驱动的轻量级代码托管解决方案。",
"name": "gitea",
"title": "Gitea",
"versions": ["1.17.2"],
"versions": ["1.17.2","1.18.5"],
"tip": "soft",
"install_pre_inspection":false,
"uninstall_pre_inspection":true,
+1 -1
View File
@@ -14,7 +14,7 @@ if [ -f ${rootPath}/bin/activate ];then
fi
URL_DOWNLOAD=https://dl.gitea.io/
URL_DOWNLOAD=https://dl.gitea.com
bash ${rootPath}/scripts/getos.sh
+3 -2
View File
@@ -187,7 +187,7 @@ function userProjectList(user, search){
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table>\
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'><ul id='gitea_page' class='page'></ul></div>\
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'><ul class='page'><div class='gitea_page'></div></ul></div>\
</div>\
</div>\
</div>",
@@ -230,7 +230,8 @@ function userProjectListPost(user, search){
var project_list = rdata['data']['data'];
for (i in project_list) {
var name = project_list[i]['name'];
list += '<tr><td>'+name+'</td>\
list += '<tr>\
<td>'+name+'</td>\
<td>\
<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+user+'/'+name+'">源码</a> | \
<a class="btlink" onclick="projectScript(\''+user+'\',\''+name+'\','+project_list[i]['has_hook']+');">脚本</a>\
+1 -1
View File
@@ -8,7 +8,7 @@
"uninstall_pre_inspection":true,
"checks": "server/mariadb",
"path": "server/mariadb",
"versions":["10.6","10.7","10.8","10.9"],
"versions":["10.6","10.7","10.8","10.9","10.11","11.0"],
"shell":"install.sh",
"checks":"server/mariadb",
"path":"server/mariadb",
+1 -1
View File
@@ -1185,7 +1185,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+119
View File
@@ -0,0 +1,119 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
#https://dev.mysql.com/downloads/file/?id=480541
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.11.2
Install_app()
{
mkdir -p ${mariadbDir}
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
if [ "$sysName" != "Darwin" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
# fi
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/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 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '安装完成' > $install_tmp
else
echo '安装失败' > $install_tmp
echo 'install fail'>&2
exit 1
fi
fi
rm -rf ${mariadbDir}/mariadb-${MY_VER}
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
}
Uninstall_app()
{
rm -rf $serverPath/mariadb
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi
+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.9
MY_VER=10.6.12
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.7.4
MY_VER=10.7.8
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.8.5
MY_VER=10.8.7
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.2
MY_VER=10.9.5
Install_app()
{
+119
View File
@@ -0,0 +1,119 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
#https://dev.mysql.com/downloads/file/?id=480541
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.0.1
Install_app()
{
mkdir -p ${mariadbDir}
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
if [ "$sysName" != "Darwin" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
# fi
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && cmake \
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/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 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '10.11' > $serverPath/mariadb/version.pl
echo '安装完成' > $install_tmp
else
echo '安装失败' > $install_tmp
echo 'install fail'>&2
exit 1
fi
fi
rm -rf ${mariadbDir}/mariadb-${MY_VER}
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
}
Uninstall_app()
{
rm -rf $serverPath/mariadb
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi
+5 -2
View File
@@ -62,13 +62,16 @@ def getArgs():
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
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
Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

+292
View File
@@ -0,0 +1,292 @@
<style>
.migration_content {
position: relative;
height: 450px;
}
.step_head::after {
background-color: #ddd;
border-top: 2px solid #ccc;
content: "";
display: block;
height: 3px;
left: 84px;
position: absolute;
top: 14px;
width: 500px;
z-index: -1;
}
.step_head {
margin: 20px 0;
}
.step_head ul li {
width: 24.5%;
display: inline-block;
}
.step_head ul li span {
width: 30px;
height: 30px;
line-height: 30px;
display: block;
border-radius: 15px;
background-color: #ddd;
color: #878787;
margin: 0 auto;
text-align: center;
font-size: 16px;
font-weight: 600;
}
.step_head ul li p {
text-align: center;
margin-top: 15px;
}
.step_head ul li.active span {
background-color: #20A53A;
color: #fff;
}
.step_content {
text-align: center;
}
.boxHide {
display: none
}
.step_content .psync_info input {
width: 300px;
}
.step_content .psync_info .panel_setp_span {
height: 32px;
line-height: 32px;
overflow: hidden;
padding-right: 20px;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
width: 130px;
display: inline-block;
float: left;
}
.step_content .psync_info .mtb20{
padding-left: 40px;
text-align: left;
}
.psync_path .table {
text-align: left;
}
.psync_path .table > tbody > tr > td:nth-child(2n),
.psync_path .table > thead > tr > th:nth-child(2n),
.terlist .table > thead > tr > th:nth-child(2n),
.terlist .table > tbody > tr > td:nth-child(2n),
.terlist .table > tbody > tr > td:nth-child(1),
.terlist .table > thead > tr > th:nth-child(1) {
border-right: #ddd 1px solid;
}
.checkbox_conten {
background-color: #f3f3f3;
border: #ddd 1px solid;
border-radius: 4px;
padding: 10px;
margin: 0px 50px;
}
.checkbox_item span {
display: inline-block;
height: 15px;
overflow: hidden;
text-align: left;
display: block;
padding-left: 20px;
height: 20px;
line-height: 20px;
width: 152px;
text-overflow: ellipsis;
}
label.checkbox_label {
margin-left: 6px;
margin-bottom: 0;
}
label.checkbox_label span {
color: #000;
}
.psync_data {
display: none;
}
.psync_data .checkbox_item input[type="checkbox"] {
width: 15px;
height: 15px;
position: absolute;
top: 50%;
margin-top: -6px;
}
.checkbox_item label {
font-weight: normal;
white-space: nowrap;
position: relative;
}
.psync_data .checkbox_data {
margin: 0 5px 5px;
display: inline-block;
width: 166px;
vertical-align: text-top;
}
.psync_data .checkbox_data:last-child {
margin-right: 0;
}
.checkbox_item ul {
background-color: #fff;
max-height: 174px;
overflow: auto;
width: 100%;
display: block;
margin-top: 10px;
}
.checkbox_item ul li {
padding: 0 6px;
}
.psync_data .checkbox_con {
display: block
}
.progress {
background-color: #e2e2e2;
border-radius: 8px;
height: 16px;
line-height: 16px;
position: relative;
}
.progress-bar {
background-color: #5ab76c;
border-radius: 8px;
height: 16px;
max-width: 100%;
position: absolute;
text-align: right;
transition: all 0.3s ease 0s;
width: 0;
}
.progress-text {
font-size: 12px;
color: #fff;
padding: 0 10px;
position: static;
}
.qystatus {
color: #666;
margin-bottom: 10px;
margin-left: 5px;
}
.success {
padding: 50px 0 60px;
margin-left: -60px;
}
.success p {
margin-top: 20px;
font-size: 16px;
color: #666;
}
.psync_tips{
color: red;
font-size: 15px;
background-color: #fbfbfb;
border: 1px solid #eee;
line-height: 46px;
margin-bottom: 15px;
padding-left: 10px;
}
.psync_tips span{
font-size: 12px;
}
</style>
<div class="migration_api pd15">
<div class="migration_content">
<div class="step_head">
<ul>
<li class="active"><span>1</span><p>填写信息</p></li>
<li><span>2</span><p>检测环境</p></li>
<li><span>3</span><p>选择数据</p></li>
<li><span>4</span><p>一键迁移</p></li>
</ul>
</div>
<div class="step_content">
<div class="pd15 psync_info">
<div class="psync_tips">
<span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>只需在发送数据服务器安装本软件,请填写<span>『 接收数据服务器 』</span>资料。
<a href="#" target="_blank" class="bt-ico-ask" style="cursor: pointer;">?</a>
</div>
<div class="mtb20">
<span class="panel_setp_span">接收数据的面板地址</span>
<input type="text" class="bt-input-text" name="sync_url" value="" placeholder="接收数据面板地址,如: http://127.0.0.1:8888">
</div>
<div class="mtb20">
<span class="panel_setp_span">接收数据的面板API</span>
<input type="text" class="bt-input-text" name="sync_token" value="" placeholder="接收数据面板API密钥" />
<a href="#" target="_blank" class="btlink ml5">获取API秘钥</a>
</div>
<div class="mtb20">
<span class="panel_setp_span">IP白名单</span>
<span style="height: 32px;line-height: 32px;">必须将本机器IP加入接收数据服务器API的IP白名单,<a href="#" href="javascript:;" target="_blank" class="btlink">如何添加白名单</a></span>
</div>
<div class="mtb20" style="text-align: left;margin-left: 130px;">
<button class="btn btn-success infoNext">下一步</button>
</div>
</div>
<div class="pa15 psync_path" style="margin:0 50px;"></div>
<div class="pa15 psync_data" style="text-align: left;">
<div class="checkbox_conten">
<div class="checkbox_data">
<div class="checkbox_item">
<label class="checkbox_label">
<input type="checkbox" id="sites_All" checked>
<span>网站</span>
</label>
<ul id="sites_li"></ul>
</div>
</div>
<div class="checkbox_data">
<div class="checkbox_item">
<label class="checkbox_label">
<input type="checkbox" id="db_All" checked>
<span>数据库</span>
</label>
<ul id="db_li"></ul>
</div>
</div>
</div>
<div class="line mtb20" style="margin:20px 0 0 50px">
<button class="btn btn-default btn-sm mr20 dataBack">上一步</button>
<button class="btn btn-success btn-sm dataMigrate">一键迁移</button>
</div>
</div>
<div class="pa15 psync_migrate"></div>
</div>
<hr style="margin-top: 5px;" />
<div class="step_footer" style="margin: 5px 0 0 20px;text-align: left;">
<ul class="help-info-text c7 mlr20" style="margin-top: 0px;">
<li>一键迁移过程中是后台执行可以关闭当前窗口</li>
<li>一键迁移迁移数据不涉及原来数据的增删(是将原来数据打包发送)</li>
</ul>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinWidth(700);
resetPluginWinWidth(700);
$.getScript( "/plugins/file?name=migration_api&f=js/app.js", function(){
initStep();
});
</script>
+1090
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
{
"sort": 7,
"ps": "[<span style='color:red;'>潜龙勿用</span>]一键迁移,仅网站数据和MySQL数据(仅支持源码安装软件)",
"name": "migration_api",
"title": "一键迁移API",
"shell": "install.sh",
"versions":["1.0"],
"updates":["1.0"],
"tip": "soft",
"checks": "server/migration_api",
"path":"server/migration_api",
"display": 1,
"author": "midoks",
"date": "2022-01-17",
"home": "https://github.com/midoks/mdserver-web",
"type": 0,
"pid": "4"
}
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=1.0
Install_App(){
mkdir -p $serverPath/migration_api
echo "${VERSION}" > $serverPath/migration_api/version.pl
echo '正在安装脚本文件...' > $install_tmp
}
Uninstall_App()
{
rm -rf $serverPath/migration_api
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+333
View File
@@ -0,0 +1,333 @@
function maPostNoMsg(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
$.post('/plugins/run', {name:'migration_api', func:method, args:_args}, 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 maPost(method,args,callback, msg = '正在获取...'){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg(msg, { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'migration_api', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function maAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
return syncPost('/plugins/run', {name:'migration_api', func:method, args:_args});
}
function maPostCallbak(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'migration_api';
req_data['func'] = method;
args['version'] = '1.0';
if (typeof(args) == 'string'){
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 selectProgress(val){
$('.step_head li').removeClass('active');
$('.step_head li').each(function(){
var v = $(this).find('span').text();
if (val == v){
$(this).addClass('active');
}
});
}
function initStep1(){
var url = $('input[name="sync_url"]').val();
var token = $('input[name="sync_token"]').val();
maPost('step_one',{url:url,token:token}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
initStep2();
}
},{ icon: rdata.status ? 1 : 2 });
},'API校验中...');
}
function initStep2(){
maPost('step_two',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
selectProgress(2);
$('.psync_info').hide();
var info = rdata.data;
var body = '<div class="divtable">\
<table class="table table-hover">\
<thead>\
<tr><th style="border-right:1px solid #ddd">服务</th><th>当前服务器</th><th>远程服务器</th></tr>\
</thead>\
<tbody>\
<tr>\
<td style="border-right:1px solid #ddd">网站服务</td>\
<td>'+info['local']['webserver']+'</td>\
<td>'+info['remote']['webserver']+'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">安装MySQL</td>\
<td>'+(info['local']['mysql']?'是':'否')+'</td>\
<td>'+(info['remote']['mysql']?'是':'否')+'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">安装PHP</td>\
<td>'+(info['local']['php'].join('/'))+'</td>\
<td>'+(info['remote']['php'].join('/')) +'</td>\
</tr>\
<tr>\
<td style="border-right:1px solid #ddd">可用磁盘</td>\
<td>'+info['local']['disk']+'</td>\
<td>'+info['remote']['disk'][0]['size'][0]+'</td>\
</tr>\
</tbody>\
</table>\
</div>';
body += '<div class="line mtb20" style="text-align: left;">\
<button class="btn btn-default btn-sm mr20 pathTestting">重新检测</button>\
<button class="btn btn-default btn-sm mr20 pathBcak">上一步</button>\
<button class="btn btn-success btn-sm psync-next pathNext">下一步</button>\
</div>';
$('.psync_path').html(body);
$('.psync_path').show();
}
},{ icon: rdata.status ? 1 : 2 });
},'检测环境中...');
}
function initStep3(){
maPost('step_three',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
if (rdata.status){
selectProgress(3);
var pdata = rdata.data;
var site_li = '';
for (var i = 0; i < pdata.sites.length; i++) {
site_li+='<li>\
<label>\
<input type="checkbox" data-id="'+i+'" id="sites_'+pdata.sites[i]['name']+'" value="'+pdata.sites[i]['name']+'" name="sites" checked="">\
<span title="'+pdata.sites[i]['name']+'">'+pdata.sites[i]['name']+'</span>\
</label>\
</li>';
}
$('#sites_li').html(site_li);
var db_li = '';
for (var i = 0; i < pdata.databases.length; i++) {
db_li+='<li>\
<label>\
<input type="checkbox" data-id="'+i+'" id="sites_'+pdata.databases[i]['name']+'" value="'+pdata.databases[i]['name']+'" name="databases" checked="">\
<span title="'+pdata.databases[i]['name']+'">'+pdata.databases[i]['name']+'</span>\
</label>\
</li>';
}
$('#db_li').html(db_li);
$('.psync_path').hide();
$('.psync_data').show();
}
},{ icon: rdata.status ? 1 : 2 });
});
}
function renderMigrationProgress(){
maPostNoMsg('get_speed',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log('speed:',rdata.data);
if (rdata.status){
if (rdata['data']['action'] == 'True'){
var end = '<div class="line">\
<div class="success text-center" style="padding: 10px 0 15px;">\
<p>数据迁移完成,请务必检查数据完整性!</p>\
<p style="font-size: 14px;margin-top:2px;color: #939292;">传输大小: '+toSize(rdata['data']['total_size'])+',耗时: '+rdata['data']['total_time']+',平均速度: '+toSize(rdata['data']['speed'])+'/s</p>\
<p class="mtb15">\
<button class="btn btn-success btn-sm mr5 okBtn">确定完成</button>\
<a class="btn btn-default btn-sm" style="margin-left: 10px;" target="_blank" href="/files/download?filename='+rdata['data']['log_file']+'">迁移日志</a>\
</p>\
</div>\
</div>';
$('.psync_migrate').html(end);
} else{
$('.psync_migrate .action').text(rdata['data']['action']);
$('.psync_migrate .done').text(rdata['data']['done']);
$('.psync_migrate pre').text(rdata['data']['log']);
var p = (rdata['data']['all_speed']/rdata['data']['all_total'])*100;
if (p>100){
p = 100;
}
$('.psync_migrate .progress_info_bar').width(p+'%');
$('.psync_migrate .progress_info').text(p+'%');
renderMigrationProgress();
}
} else{
layer.msg(rdata.msg,{icon:1});
}
});
}
function initStep4(){
var site_checked = '';
$('input[name="sites"]:checked').each(function(){
site_checked += $(this).val()+',';
});
var databases_checked = '';
$('input[name="databases"]:checked').each(function(){
databases_checked+=$(this).val()+',';
});
maPost('step_four',{sites:site_checked,databases:databases_checked}, function(rdata){
var rdata = $.parseJSON(rdata.data);
selectProgress(4);
var progress = '<div style="margin: 0 40px;">\
<div class="line">\
<div style="text-align:left"><span class="action">--</span>\
<span style="margin-left: 20px;" class="done">当前: --</span><img src="/static/img/ing.gif"><a style="position: absolute;right: 40px;" class="btlink psync_close" onclick="migrate.close();">[取消]</a></div>\
<div class="bt-progress" style="border-radius:0;height:20px;line-height:19px">\
<div class="bt-progress-bar progress_info_bar" style="border-radius: 0px; height: 20px; width: 0%;">\
<span class="bt-progress-text progress_info"></span></div>\
</div>\
</div>\
</div>\
<pre style="height: 222px;text-align: left;margin:5px 38px 0;font-size: 12px;line-height: 20px;padding: 10px;background-color: #333;color: #fff;"></pre>\
</div>';
$('.psync_data').hide();
$('.psync_migrate').html(progress);
$('.psync_migrate').show();
renderMigrationProgress();
});
}
function initStep(){
maPost('get_conf',{}, function(rdata){
var rdata = $.parseJSON(rdata.data);
$('input[name="sync_url"]').val(rdata.data['url']);
$('input[name="sync_token"]').val(rdata.data['token']);
});
$('.infoNext').click(function(){
initStep1();
});
// 重新检测按钮
$('.psync_path').on('click', '.pathTestting', function () {
initStep2();
});
$('.psync_path').on('click', '.pathBcak', function(){
$('.psync_path').hide();
$('.psync_info').show();
selectProgress(1);
});
$('.psync_path').on('click', '.pathNext', function(){
initStep3();
});
$('.psync_data').on('click', '.dataBack', function(){
$('.psync_data').hide();
$('.psync_path').show();
selectProgress(2);
});
$('.psync_data').on('click', '.dataMigrate', function(){
initStep4();
});
$('#sites_All').on('click',function(){
var ch = $(this).prop('checked');
$('#sites_li input').prop('checked',ch);
});
$('#db_All').on('click',function(){
var ch = $(this).prop('checked');
$('#db_li input').prop('checked',ch);
});
$('.psync_migrate').on('click', '.okBtn', function(){
$('.psync_migrate').hide();
$('.psync_info').show();
selectProgress(1);
});
}
+1
View File
@@ -65,6 +65,7 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -62,6 +62,7 @@ binlog-ignore-db = performance_schema
#slave
log_replica_updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+5 -1
View File
@@ -2474,7 +2474,8 @@ def doFullSyncUser(version=''):
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
port + " -u" + user + " -p" + apass + \
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
@@ -2682,6 +2683,9 @@ def uninstallPreInspection(version):
if mw.isDebugMode():
return 'ok'
import plugins_api
plugins_api.plugins_api().removeIndex(getPluginName(), version)
return "请手动删除MySQL[{}]<br/> rm -rf {}".format(version, getServerDir())
if __name__ == "__main__":
+1 -1
View File
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+1
View File
@@ -66,6 +66,7 @@ binlog-ignore-db = performance_schema
#slave
log-slave-updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1
View File
@@ -62,6 +62,7 @@ binlog-ignore-db = performance_schema
#slave
log_replica_updates
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+5 -1
View File
@@ -2434,7 +2434,8 @@ def doFullSyncUser(version=''):
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
port + " -u" + user + " -p" + apass + \
" --ssl-mode=DISABLED " + sync_db + " > " + bak_file
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
@@ -2639,6 +2640,9 @@ def uninstallPreInspection(version):
if mw.isDebugMode():
return 'ok'
import plugins_api
plugins_api.plugins_api().removeIndex(getPluginName(), version)
return "请手动删除MySQL[{}]<br/> rm -rf {}".format(version, getServerDir())
if __name__ == "__main__":
+1 -1
View File
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+2 -1
View File
@@ -39,7 +39,7 @@ max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
skip-name-resolve=1
skip_name_resolve=1
#skip-grant-tables
#skip-networking
#skip-external-locking
@@ -70,6 +70,7 @@ log-slave-updates = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+2 -1
View File
@@ -41,7 +41,7 @@ max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
skip-name-resolve=1
skip_name_resolve=1
#skip-grant-tables
#skip-networking
#skip-external-locking
@@ -72,6 +72,7 @@ log-slave-updates = 1
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+4 -2
View File
@@ -17,6 +17,7 @@ datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
server-id = {$SERVER_ID}
explicit_defaults_for_timestamp=true
default_storage_engine = InnoDB
@@ -40,7 +41,7 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
skip_name_resolve = 1
skip_name_resolve=1
skip-ssl
#skip-networking
#skip-external-locking
@@ -73,6 +74,7 @@ binlog-ignore-db = performance_schema
# Prevent replication from starting automatically with MySQL
#skip-slave-start = 1
#replicate-do-db
slave_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
@@ -94,7 +96,7 @@ innodb_file_per_table = 1
innodb_large_prefix = 1
secure-file-priv={$SERVER_APP_PATH}/tmp
#secure-file-priv=disabled
[mysqldump]
quick
+2 -1
View File
@@ -40,7 +40,7 @@ max_connect_errors = 100
open_files_limit = 2560
max_allowed_packet = 128M
skip_name_resolve = 1
skip_name_resolve=1
#skip-networking
#skip-external-locking
#loose-skip-innodb
@@ -71,6 +71,7 @@ log_replica_updates = 1
# Prevent replication from starting automatically with MySQL
#skip_replica_start = 1
#replicate-do-db
replica_skip_errors=1062
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = mysql
+1 -1
View File
@@ -16,7 +16,7 @@
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 530px; overflow: auto;"></div>
<div class="soft-man-con"></div>
</div>
</div>
+72 -14
View File
@@ -48,19 +48,20 @@ def getInitDFile():
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
if t.strip() == '':
tmp = []
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(':')
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
@@ -382,7 +383,7 @@ def initMysql57Data():
myconf = serverdir + "/etc/my.cnf"
user = pGetDbUser()
cmd = 'cd ' + serverdir + ' && ./bin/mysqld --defaults-file=' + myconf + \
' --initialize-insecure --explicit_defaults_for_timestamp'
' --initialize-insecure --explicit_defaults_for_timestamp --user=mysql'
data = mw.execShell(cmd)
# print(data)
return False
@@ -842,12 +843,29 @@ def setDbBackup():
return data[1]
scDir = mw.getRunDir() + '/scripts/backup.py'
cmd = 'python3 ' + scDir + ' database ' + args['name'] + ' 3'
os.system(cmd)
return mw.returnJson(True, 'ok')
# 数据库密码处理
def myPass(act, root):
conf_file = getConf()
mw.execShell("sed -i '/user=root/d' {}".format(conf_file))
mw.execShell("sed -i '/password=/d' {}".format(conf_file))
if act:
mycnf = mw.readFile(conf_file)
src_dump = "[mysqldump]\n"
sub_dump = src_dump + "user=root\npassword=\"{}\"\n".format(root)
if not mycnf:
return False
mycnf = mycnf.replace(src_dump, sub_dump)
if len(mycnf) > 100:
mw.writeFile(conf_file, mycnf)
return True
return True
def importDbExternal():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
@@ -902,11 +920,16 @@ def importDbExternal():
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
os.environ["MYSQL_PWD"] = pwd
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + \
pwd + ' ' + name + ' < ' + import_sql
my_cnf = getConf()
myPass(True, pwd)
mysql_cmd = getServerDir() + '/bin/mysql --defaults-file=' + my_cnf + \
' -uroot -p\"' + pwd + '\" -f ' + name + ' < ' + import_sql
# print(mysql_cmd)
rdata = mw.execShell(mysql_cmd)
myPass(False, pwd)
# print(rdata)
if ext != 'sql':
os.remove(import_sql)
@@ -2371,6 +2394,25 @@ def initSlaveStatus(version=''):
return initSlaveStatusSyncUser(version)
def makeSyncUsercmd(u, version=''):
mode = recognizeDbMode()
sql = ''
ip = u['ip']
port = u['port']
username = u['user']
password = u['pass']
if mode == "gtid":
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
username + "', MASTER_PASSWORD='" + \
password + "', MASTER_AUTO_POSITION=1"
if version == '8.0':
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
username + "', SOURCE_PASSWORD='" + \
password + "', MASTER_AUTO_POSITION=1"
return sql
def initSlaveStatusSyncUser(version=''):
conn = pSqliteDb('slave_sync_user')
data = conn.field('ip,port,user,pass,mode,cmd').find()
@@ -2393,8 +2435,19 @@ def initSlaveStatusSyncUser(version=''):
if local_mode != mode_name:
return mw.returnJson(False, '同步模式不一致!')
t = db.query(u['cmd'])
# print(t)
if u['cmd'] == '' and local_mode == 'gtid':
sql = makeSyncUsercmd(u, version)
# print(sql)
t = db.query(sql)
else:
if u['cmd'] == '':
return mw.returnJson(False, '经典模式下,必须手写同步命令!')
# print(u['cmd'])
t = db.query(u['cmd'])
isError = isSqlError(t)
if isError:
return isError
db.query("start slave user='{}' password='{}';".format(
u['user'], u['pass']))
return mw.returnJson(True, '初始化成功!')
@@ -2612,8 +2665,10 @@ def doFullSyncUser(version=''):
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 20})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
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)
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
@@ -2804,6 +2859,9 @@ def uninstallPreInspection(version):
if mw.isDebugMode():
return 'ok'
import plugins_api
plugins_api.plugins_api().removeIndex(getPluginName(), version)
return "请手动删除MySQL[{}]<br/> rm -rf {}".format(version, getServerDir())
if __name__ == "__main__":
+2 -2
View File
@@ -181,7 +181,7 @@ function changeMySQLDataPath(act) {
$.post('/database?action=GetMySQLInfo', '', function(rdata) {
var LimitCon = '<p class="conf_p">\
<input id="datadir" class="phpUploadLimit bt-input-text mr5" style="width:350px;" type="text" value="' + rdata.datadir + '" name="datadir">\
<span onclick="ChangePath(\'datadir\')" class="glyphicon glyphicon-folder-open cursor mr20" style="width:auto"></span><button class="btn btn-success btn-sm" onclick="changeMySQLDataPath(1)">' + lan.soft.mysql_to + '</button>\
<span onclick="changePath(\'datadir\')" class="glyphicon glyphicon-folder-open cursor mr20" style="width:auto"></span><button class="btn btn-success btn-sm" onclick="changeMySQLDataPath(1)">' + lan.soft.mysql_to + '</button>\
</p>';
$(".soft-man-con").html(LimitCon);
});
@@ -1208,7 +1208,7 @@ function myLogs(){
<span class="f14 c6 mr20">二进制日志 </span><span class="f14 c6 mr20">' + toSize(rdata.msg) + '</span>\
'+line_status+'\
<p class="f14 c6 mtb10" style="border-top:#ddd 1px solid; padding:10px 0">错误日志<button class="btn btn-default btn-clear btn-xs" style="float:right;" >清理日志</button></p>\
<textarea readonly style="margin: 0px;width: 100%;height: 440px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
<textarea readonly style="margin: 0px;width: 100%;height: 438px;background-color: #333;color:#fff; padding:0 5px" id="error_log"></textarea>\
</p>';
$(".soft-man-con").html(limitCon);
+1
View File
@@ -86,6 +86,7 @@ Install_mysql()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mysql ];then
rm -rf ${mysqlDir}/mysql-${VERSION}
echo '5.5' > $serverPath/mysql/version.pl
echo '安装完成' > $install_tmp
else
+1
View File
@@ -105,6 +105,7 @@ Install_mysql()
if [ -d $serverPath/mysql ];then
rm -rf ${mysqlDir}/mysql-${VERSION}
echo '5.6' > $serverPath/mysql/version.pl
echo '安装完成' > $install_tmp
else
+1
View File
@@ -118,6 +118,7 @@ Install_mysql()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mysql ];then
rm -rf ${mysqlDir}/mysql-${VERSION}
echo '5.7' > $serverPath/mysql/version.pl
echo '安装完成' > $install_tmp
else
+1
View File
@@ -210,6 +210,7 @@ Install_mysql()
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mysql ];then
rm -rf ${mysqlDir}/mysql-${VERSION}
echo '8.0' > $serverPath/mysql/version.pl
echo '安装完成' > $install_tmp
else
Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

+26
View File
@@ -0,0 +1,26 @@
<div class="bt-form">
<div class="bt-w-main">
<div class='plugin_version'></div>
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('nezha',$('.plugin_version').attr('version'));">面板服务</p>
<p onclick="pluginInitD('nezha',$('.plugin_version').attr('version'));">面板自启动</p>
<p onclick="nezha.cfg($('.plugin_version').attr('version'));">面板配置</p>
<p onclick="pluginConfig('nezha', $('.plugin_version').attr('version'), 'conf');">面板配置文件</p>
<p onclick="pluginService('nezha', $('.plugin_version').attr('version'), 'agent');">AGENT服务</p>
<p onclick="pluginInitD('nezha', $('.plugin_version').attr('version'), 'agent');">AGENT自启动</p>
<p onclick="nezha.agent_cfg($('.plugin_version').attr('version'));">AGENT配置</p>
<p onclick="nezha.readme();">说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(530);
$.getScript( "/plugins/file?name=nezha&f=js/nezha.js", function(){
nezha.init();
pluginService('nezha');
});
</script>
+364
View File
@@ -0,0 +1,364 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import socket
import json
from datetime import datetime
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
class App:
__setupPath = '/www/server/nezha'
__cfg = ''
__agent_cfg = ''
def __init__(self):
self.__setupPath = self.getServerDir()
self.__cfg = self.__setupPath + '/nezha.cfg'
self.__agent_cfg = self.__setupPath + '/agent.cfg'
def getArgs(self):
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':', 1)
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(self, 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 __release_port(self, port):
from collections import namedtuple
try:
import firewall_api
firewall_api.firewall_api().addAcceptPortArgs(port, 'nezha', 'port')
return port
except Exception as e:
return "Release failed {}".format(e)
def openPort(self):
for i in ["9527", "5555"]:
self.__release_port(i)
return True
def getPluginName(self):
return 'nezha'
def getPluginDir(self):
return mw.getPluginDir() + '/' + self.getPluginName()
def getServerDir(self):
return mw.getServerDir() + '/' + self.getPluginName()
def getInitdConfTpl(self):
path = self.getPluginDir() + "/init.d/nezha.tpl"
return path
def getInitdAgentConfTpl(self):
path = self.getPluginDir() + "/init.d/nezha-agent.tpl"
return path
def getHomeDir(self):
if mw.isAppleSystem():
user = mw.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
return '/Users/' + user
else:
return '/root'
def getRunUser(self):
if mw.isAppleSystem():
user = mw.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
return user
else:
return 'root'
def status(self):
cmd = "ps -ef|grep " + self.getPluginName() + \
" |grep -v grep | grep -v nezha-agent | grep -v python | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return "stop"
return 'start'
def status_agent(self):
cmd = "ps -ef | grep nezha-agent | grep -v grep | grep -v python | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return 'stop'
return 'start'
def contentReplace(self, content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$RUN_USER}', self.getRunUser())
content = content.replace('{$HOME_DIR}', self.getHomeDir())
return content
def initDreplace(self):
file_tpl = self.getInitdConfTpl()
service_path = mw.getServerDir()
initD_path = self.getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
self.openPort()
file_bin = initD_path + '/' + self.getPluginName()
if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = self.contentReplace(content)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/nezha.service'
systemServiceTpl = self.getPluginDir() + '/init.d/nezha.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = self.contentReplace(se_content)
mw.writeFile(systemService, se_content)
mw.execShell('systemctl daemon-reload')
return file_bin
def contentAgentReplace(self, content):
path = self.__agent_cfg
if os.path.exists(path):
data = self.get_agent_cfg()
content = content.replace('{$APP_HOST}', data['host'])
content = content.replace('{$APP_SECRET}', data['secret'])
return content
def initDAgent(self):
file_tpl = self.getInitdAgentConfTpl()
initD_path = self.getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_agent_bin = initD_path + '/nezha-agent'
content = mw.readFile(file_tpl)
content = self.contentReplace(content)
content = self.contentAgentReplace(content)
mw.writeFile(file_agent_bin, content)
mw.execShell('chmod +x ' + file_agent_bin)
# systemd
sysDir = mw.systemdCfgDir()
sysService = sysDir + '/nezha-agent.service'
sysServiceTpl = self.getPluginDir() + '/init.d/nezha-agent.service.tpl'
service_path = mw.getServerDir()
content = mw.readFile(sysServiceTpl)
content = self.contentReplace(content)
content = self.contentAgentReplace(content)
mw.writeFile(sysService, content)
mw.execShell('systemctl daemon-reload')
return file_agent_bin
def init_cfg(self):
self.initDreplace()
self.initDAgent()
def imOp(self, method):
file = self.initDreplace()
if not mw.isAppleSystem():
cmd = 'systemctl {} {}'.format(method, self.getPluginName())
data = mw.execShell(cmd)
if data[1] == '':
return 'ok'
return 'fail'
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[0]
def start(self):
return self.imOp('start')
def stop(self):
return self.imOp('stop')
def restart(self):
return self.imOp('restart')
def reload(self):
return self.imOp('reload')
def agOp(self, method):
file = self.initDAgent()
path = self.__agent_cfg
if not os.path.exists(path):
return '请先设置Agent配置!'
if not mw.isAppleSystem():
cmd = 'systemctl {} {}'.format(method, 'nezha-agent')
data = mw.execShell(cmd)
if data[1] == '':
return 'ok'
return 'fail'
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[0]
def start_agent(self):
return self.agOp('start')
def stop_agent(self):
return self.agOp('stop')
def restart_agent(self):
return self.agOp('restart')
def reload_agent(self):
return self.agentOp('reload')
def initd_status(self):
cmd = 'systemctl status nezha | grep loaded | grep "enabled;"'
data = mw.execShell(cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initd_install(self):
mw.execShell('systemctl enable nezha')
return 'ok'
def initd_uninstall(self):
mw.execShell('systemctl disable nezha')
return 'ok'
def initd_status_agent(self):
cmd = 'systemctl status nezha-agent | grep loaded | grep "enabled;"'
data = mw.execShell(cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initd_install_agent(self):
mw.execShell('systemctl enable nezha-agent')
return 'ok'
def initd_uninstall_agent(self):
mw.execShell('systemctl disable nezha-agent')
return 'ok'
def conf(self):
return self.getServerDir() + '/dashboard/data/config.yaml'
def nezha_cfg(self):
path = self.__cfg
if not os.path.exists(path):
d = {}
cmd_un = 'cd ' + self.getServerDir() + '/dashboard && ./nezha conf -u ""'
mw.execShell(cmd_un)
td = mw.execShell(cmd_un)
d['username'] = td[0].strip()
pwd = mw.getRandomString(16)
cmd_pwd = 'cd ' + self.getServerDir() + '/dashboard && ./nezha conf -u "" -p ' + pwd
td = mw.execShell(cmd_pwd)
d['password'] = pwd
mw.writeFile(path, mw.enDoubleCrypt('nezha', mw.getJson(d)))
info = mw.readFile(path)
info = mw.deDoubleCrypt('nezha', info)
info = json.loads(info)
return mw.returnJson(True, 'ok', info)
def nezha_save_cfg(self):
args = self.getArgs()
data = self.checkArgs(args, ['username', 'password'])
if not data[0]:
return data[1]
path = self.__cfg
cmd = 'cd ' + self.getServerDir() + '/dashboard && ./nezha conf -su "' + \
args['username'] + '" -p ' + args['password']
# print(cmd)
t = mw.execShell(cmd)
# print(t)
mw.writeFile(path, mw.enDoubleCrypt('nezha', mw.getJson(args)))
return mw.returnJson(True, '修改成功!')
def get_agent_cfg(self):
path = self.__agent_cfg
info = mw.readFile(path)
info = mw.deDoubleCrypt('agent', info)
info = json.loads(info)
return info
def agent_cfg(self):
path = self.__agent_cfg
if not os.path.exists(path):
d = {}
d['host'] = '127.0.0.1:5555'
d['secret'] = 'secret'
mw.writeFile(path, mw.enDoubleCrypt('agent', mw.getJson(d)))
info = self.get_agent_cfg()
return mw.returnJson(True, 'ok', info)
def agent_save_cfg(self):
args = self.getArgs()
data = self.checkArgs(args, ['host', 'secret'])
if not data[0]:
return data[1]
path = self.__agent_cfg
mw.writeFile(path, mw.enDoubleCrypt('agent', mw.getJson(args)))
return mw.returnJson(True, '修改成功!')
def run_log(self):
return self.getServerDir() + '/logs/nezha.log'
if __name__ == "__main__":
func = sys.argv[1]
classApp = App()
try:
data = eval("classApp." + func + "()")
print(data)
except Exception as e:
print('error:' + str(e))
+18
View File
@@ -0,0 +1,18 @@
{
"sort": 7,
"ps": "哪吒监控面板/改造版",
"name": "nezha",
"title": "哪吒监控",
"shell": "install.sh",
"versions":["0.15.2"],
"tip": "soft",
"checks": "server/nezha",
"path": "server/nezha",
"display": 1,
"author": "midoks",
"date": "2023-06-26",
"home": "https://github.com/midoks/nezha",
"doc1": "https://nezha.wiki/",
"type": 0,
"pid": "5"
}
@@ -0,0 +1,30 @@
[Unit]
Description=Nezha Agent
After=syslog.target
#After=network.target
#After=nezha-dashboard.service
[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
Type=simple
User=root
Group=root
WorkingDirectory={$SERVER_PATH}/nezha/agent/
ExecStart={$SERVER_PATH}/nezha/agent/nezha-agent -s {$APP_HOST} -p {$APP_SECRET}
Restart=always
#Environment=DEBUG=true
# Some distributions may not support these hardening directives. If you cannot start the service due
# to an unknown option, comment out the ones not supported by your version of systemd.
#ProtectSystem=full
#PrivateDevices=yes
#PrivateTmp=yes
#NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
+90
View File
@@ -0,0 +1,90 @@
#!/bin/bash
# chkconfig: 2345 55 25
# description: Nezha Agent Service
### BEGIN INIT INFO
# Provides: Nezha Agent
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts Nezha Agent
# Description: starts the Nezha Agent
### END INIT INFO
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
if [ -f /etc/init.d/functions ];then
. /etc/init.d/functions
fi
if [ -f /etc/rc.d/init.d/functions ];then
. /etc/rc.d/init.d/functions
fi
SERVICENAME=nezha-agent
LOG_PATH={$SERVER_PATH}/nezha/logs
APP_PATH={$SERVER_PATH}/nezha/agent
APP_HOST={$APP_HOST}
APP_SECRET={$APP_SECRET}
app_start(){
isStart=`ps -ef|grep "${SERVICENAME}" | grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "Starting ${SERVICENAME}... \c"
cd $APP_PATH
exec nohup ${APP_PATH}/${SERVICENAME} -d -s ${APP_HOST} -p ${APP_SECRET} >> ${LOG_PATH}/${SERVICENAME}.log 2>&1 &
isStart=""
while [[ "$isStart" == "" ]];
do
echo -e ".\c"
sleep 0.5
isStart=$(ps -ef|grep "${SERVICENAME}" |grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}')
let n+=1
if [ $n -gt 15 ];then
break;
fi
done
if [ "$isStart" == '' ];then
echo -e "\033[31mError: ${SERVICENAME} service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting ${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
app_stop(){
pids=`ps -ef | grep "${SERVICENAME}" | grep -v grep | grep -v python | grep -v "/bin/bash" |awk '{print $2}'`
arr=($pids)
echo -e "Stopping ${SERVICENAME}... \c"
for p in ${arr[@]}
do
# echo "$p"
kill -9 $p
done
echo -e "\033[32mdone\033[0m"
}
app_status(){
isStart=`ps -ef | grep "${SERVICENAME}" | grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "${SERVICENAME} not running"
else
echo -e "${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
case "$1" in
'start') app_start;;
'stop') app_stop;;
'status') app_status;;
'reload')
app_stop
app_start;;
'restart')
app_stop
app_start;;
esac
+30
View File
@@ -0,0 +1,30 @@
[Unit]
Description=Nezha Dashborad
After=syslog.target
After=network.target
After=mariadb.service mysqld.service postgresql.service memcached.service redis.service
[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
Type=simple
#User=root
#Group=root
WorkingDirectory={$SERVER_PATH}/nezha/dashboard/
ExecStart={$SERVER_PATH}/nezha/dashboard/nezha web
Restart=always
#Environment=DEBUG=true
# Some distributions may not support these hardening directives. If you cannot start the service due
# to an unknown option, comment out the ones not supported by your version of systemd.
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
+87
View File
@@ -0,0 +1,87 @@
#!/bin/bash
# chkconfig: 2345 55 25
# description: Nezha Service
### BEGIN INIT INFO
# Provides: Nezha
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts Nezha
# Description: starts the Nezha
### END INIT INFO
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
if [ -f /etc/init.d/functions ];then
. /etc/init.d/functions
fi
if [ -f /etc/rc.d/init.d/functions ];then
. /etc/rc.d/init.d/functions
fi
SERVICENAME=nezha
LOG_PATH={$SERVER_PATH}/${SERVICENAME}/logs
APP_PATH={$SERVER_PATH}/${SERVICENAME}/dashboard
app_start(){
isStart=`ps -ef|grep "${SERVICENAME} web" | grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "Starting ${SERVICENAME}... \c"
cd $APP_PATH && exec nohup ${APP_PATH}/${SERVICENAME} web >> ${LOG_PATH}/${SERVICENAME}.log 2>&1 &
isStart=""
while [[ "$isStart" == "" ]];
do
echo -e ".\c"
sleep 0.5
isStart=$(ps -ef|grep "${SERVICENAME} web" |grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}')
let n+=1
if [ $n -gt 15 ];then
break;
fi
done
if [ "$isStart" == '' ];then
echo -e "\033[31mError: ${SERVICENAME} service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting ${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
app_stop(){
pids=`ps -ef | grep "${SERVICENAME} web" | grep -v grep | grep -v python | grep -v "/bin/bash" |awk '{print $2}'`
arr=($pids)
echo -e "Stopping ${SERVICENAME}... \c"
for p in ${arr[@]}
do
# echo "$p"
kill -9 $p
done
echo -e "\033[32mdone\033[0m"
}
app_status(){
isStart=`ps -ef | grep "${SERVICENAME} web" | grep -v grep | grep -v python | grep -v "/bin/bash" | awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "${SERVICENAME} not running"
else
echo -e "${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
case "$1" in
'start') app_start;;
'stop') app_stop;;
'status') app_status;;
'reload')
app_stop
app_start;;
'restart')
app_stop
app_start;;
esac
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
action=$1
type=$2
if [ "${2}" == "" ];then
echo '缺少安装脚本...' > $install_tmp
exit 0
fi
if [ ! -d $curPath/versions/$2 ];then
echo '缺少安装脚本2...' > $install_tmp
exit 0
fi
sh -x $curPath/versions/$2/install.sh $1
if [ "${action}" == "uninstall" ];then
if [ -f /usr/lib/systemd/system/nezha.service ] || [ -f /lib/systemd/system/nezha.service ] ;then
systemctl stop nezha
systemctl disable nezha
rm -rf /usr/lib/systemd/system/nezha.service
rm -rf /lib/systemd/system/nezha.service
systemctl daemon-reload
fi
if [ -f /usr/lib/systemd/system/nezha-agent.service ] || [ -f /lib/systemd/system/nezha-agent.service ] ;then
systemctl stop nezha-agent
systemctl disable nezha-agent
rm -rf /usr/lib/systemd/system/nezha-agent.service
rm -rf /lib/systemd/system/nezha-agent.service
systemctl daemon-reload
fi
fi
+184
View File
@@ -0,0 +1,184 @@
var nezha = {
plugin_name: 'nezha',
init: function () {
var _this = this;
},
send:function(info){
var tips = info['tips'];
var method = info['method'];
var args = info['data'];
var callback = info['success'];
var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 });
var data = {};
data['name'] = 'nezha';
data['func'] = method;
data['version'] = $('.plugin_version').attr('version');
if (typeof(args) == 'string'){
data['args'] = JSON.stringify(toArrayObject(args));
} else {
data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', data, function(res) {
layer.close(loadT);
if (!res.status){
layer.msg(res.msg,{icon:2,time:10000});
return;
}
var ret_data = $.parseJSON(res.data);
console.log("send:",ret_data);
// if (!ret_data.status){
// layer.msg(ret_data.msg,{icon:2,time:2000});
// return;
// }
// console.log("send2:",ret_data);
if(typeof(callback) == 'function'){
callback(ret_data);
}
},'json');
},
postCallback:function(info){
var tips = info['tips'];
var method = info['method'];
var args = info['data'];
var callback = info['success'];
var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 });
var data = {};
data['name'] = 'nezha';
data['func'] = method;
data['version'] = $('.plugin_version').attr('version');
if (typeof(args) == 'string'){
data['args'] = JSON.stringify(toArrayObject(args));
} else {
data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', data, function(res) {
layer.close(loadT);
if (!res.status){
layer.msg(res.msg,{icon:2,time:10000});
return;
}
var ret_data = $.parseJSON(res.data);
if (!ret_data.status){
layer.msg(ret_data.msg,{icon:2,time:2000});
return;
}
if(typeof(callback) == 'function'){
callback(res);
}
},'json');
},
repeatPwd:function (a, id) {
$("#"+id).val(randomStrPwd(a))
},
save_cfg:function(version){
var username = $("input[name='username']").val();
var password = $("input[name='password']").val();
this.send({
tips:'正在设置中...',
data:{'username':username,'password':password},
method:'nezha_save_cfg',
success:function(rdata){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
}
});
},
cfg:function(version){
this.send({
tips:'正在获取中...',
method:'nezha_cfg',
success:function(data){
var d = data.data;
var value = '<p>\
<span>用户名</span>\
<input id="nz_username" style="width: 160px;" class="bt-input-text mr5" name="username" value="'+d['username']+'" type="text">\
,<span title="随机用户名" class="glyphicon glyphicon-repeat cursor" onclick="nezha.repeatPwd(8,\'nz_username\')"></span>\
</p>';
value += '<p>\
<span>密码</span>\
<input id="nz_password" style="width: 160px;" class="bt-input-text mr5" name="password" value="'+d['password']+'" type="text">\
,<span title="随机密码" class="glyphicon glyphicon-repeat cursor" onclick="nezha.repeatPwd(16,\'nz_password\')"></span>\
</p>';
var conf = '<style>.conf_p p{margin-bottom: 2px;} .conf_p span {width: 50px;}</style><div class="conf_p" style="margin-bottom:0">\
' + value + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm mr5" onclick="nezha.cfg(\'' + version + '\')">刷新</button>\
<button class="btn btn-success btn-sm" onclick="nezha.save_cfg(\'' + version + '\')">保存</button>\
</div>\
</div>'
$(".soft-man-con").html(conf);
}
});
},
agent_save_cfg:function(version){
var host = $("input[name='host']").val();
var secret = $("input[name='secret']").val();
this.send({
tips:'正在设置中...',
data:{'host':host,'secret':secret},
method:'agent_save_cfg',
success:function(rdata){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
}
});
},
agent_cfg:function(version){
this.send({
tips:'正在获取中...',
method:'agent_cfg',
success:function(data){
var d = data.data;
var value = '<p>\
<span>地址</span>\
<input id="nz_username" style="width: 160px;" class="bt-input-text mr5" name="host" value="'+d['host']+'" type="text">\
,<font>如1.1.1.1:5444</font>\
</p>';
value += '<p>\
<span>密钥</span>\
<input id="nz_password" style="width: 160px;" class="bt-input-text mr5" name="secret" value="'+d['secret']+'" type="text">\
,<font>密钥</font>\
</p>';
var conf = '<style>.conf_p p{margin-bottom: 2px;} .conf_p span {width: 50px;}</style><div class="conf_p" style="margin-bottom:0">\
' + value + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm mr5" onclick="nezha.agent_cfg(\'' + version + '\')">刷新</button>\
<button class="btn btn-success btn-sm" onclick="nezha.agent_save_cfg(\'' + version + '\')">保存</button>\
</div>\
</div>'
$(".soft-man-con").html(conf);
}
});
},
readme:function (){
var readme = '<ul class="help-info-text c7">';
readme += '<li>安装时不会自动启动。</li>';
readme += '<li>哪吒面板是改造版,用户名和密码登录【面板配置】,不依赖github/gitee/gitlab。</li>';
readme += '<li>Agent需要先手动填写正确信息。</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}
}
+158
View File
@@ -0,0 +1,158 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=0.15.2
# bash install.sh install 0.15.2
# cd /www/server/mdserver-web/plugins/nezha && bash install.sh install 0.15.2
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/nezha && bash install.sh install 0.15.2
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
ARCH="amd64"
get_arch() {
TMP_ARCH=`arch`
if [ "$TMP_ARCH" == "x86_64" ];then
ARCH="amd64"
elif [ "$TMP_ARCH" == "aarch64" ];then
ARCH="arm64"
else
echo $ARCH
fi
}
load_vars() {
OS=$(uname | tr '[:upper:]' '[:lower:]')
TARGET_DIR="$serverPath/nezha/dashboard"
## China_IP
if [[ -z "${CN}" ]]; then
if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
CN=true
fi
fi
if [[ -z "${CN}" ]]; then
GITHUB_RAW_URL="raw.githubusercontent.com/midoks/nezha/main"
GITHUB_URL="github.com"
else
GITHUB_RAW_URL="cdn.jsdelivr.net/gh/midoks/nezha@main"
GITHUB_URL="dn-dao-github-mirror.daocloud.io"
fi
echo $GITHUB_RAW_URL
echo $GITHUB_URL
}
# download file
download_file() {
url="${1}"
destination="${2}"
printf "Fetching ${url} \n\n"
if test -x "$(command -v curl)"; then
code=$(curl --connect-timeout 15 -w '%{http_code}' -L "${url}" -o "${destination}")
elif test -x "$(command -v wget)"; then
code=$(wget -t2 -T15 -O "${destination}" --server-response "${url}" 2>&1 | awk '/^ HTTP/{print $2}' | tail -1)
else
printf "\e[1;31mNeither curl nor wget was available to perform http requests.\e[0m\n"
exit 1
fi
if [ "${code}" != 200 ]; then
printf "\e[1;31mRequest failed with code %s\e[0m\n" $code
exit 1
else
printf "\n\e[1;33mDownload succeeded\e[0m\n"
fi
}
Install_dashborad(){
echo '正在安装哪吒监控...' > $install_tmp
mkdir -p $serverPath/source
if [ ! -f $TARGET_DIR/nezha ];then
DOWNLOAD_URL="https://${GITHUB_URL}/midoks/nezha/releases/download/v${VERSION}/nezha-${OS}-${ARCH}.zip"
DOWNLOAD_FILE="$(mktemp).zip"
download_file $DOWNLOAD_URL $DOWNLOAD_FILE
if [ ! -d $TARGET_DIR ]; then
mkdir -p $TARGET_DIR
fi
unzip $DOWNLOAD_FILE -d $TARGET_DIR
rm -rf $DOWNLOAD_FILE
fi
}
Install_agent(){
echo -e "正在下载监控端" > $install_tmp
mkdir -p $serverPath/source
version=v0.15.1
AGENT_TARGET_DIR="$serverPath/nezha/agent"
DOWNLOAD_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_${OS}_${ARCH}.zip"
DOWNLOAD_FILE="$(mktemp).zip"
if [ ! -f $AGENT_TARGET_DIR/nezha-agent ];then
download_file $DOWNLOAD_URL $DOWNLOAD_FILE
if [ ! -d $AGENT_TARGET_DIR ]; then
mkdir -p $AGENT_TARGET_DIR
fi
unzip $DOWNLOAD_FILE -d $AGENT_TARGET_DIR
rm -rf $DOWNLOAD_FILE
fi
}
Install_App()
{
load_vars
get_arch
Install_dashborad
Install_agent
if [ -d $serverPath/nezha ];then
echo "$VERSION" > $serverPath/nezha/version.pl
cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py init_cfg
fi
echo 'install successful' > $install_tmp
}
Uninstall_App()
{
cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py initd_uninstall
cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py initd_uninstall_agent
cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py stop
cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py stop_agent
rm -rf $serverPath/nezha
echo "install fail" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
@@ -0,0 +1,2 @@
## 指定共享内存
lua_shared_dict healthcheck 10m;
@@ -0,0 +1,64 @@
location / {
proxy_pass http://{$UPSTREAM_NAME};
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $proxy_host;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
#location /upstream_status {
# allow 127.0.0.1;
# deny all;
# access_log off;
# default_type text/plain;
# content_by_lua_block {
# local hc = require "resty.upstream.healthcheck"
# ngx.say("OpenResty Worker PID: ", ngx.worker.pid())
# ngx.print(hc.status_page())
# }
#}
location /upstream_status_{$UPSTREAM_NAME} {
allow 127.0.0.1;
deny all;
access_log off;
default_type text/plain;
content_by_lua_block {
local json = require "cjson"
local ok, upstream = pcall(require, "ngx.upstream")
if not ok then
ngx.print("[]")
return
end
local get_primary_peers = upstream.get_primary_peers
local get_backup_peers = upstream.get_backup_peers
local upstream_name = "{$UPSTREAM_NAME}"
peers, err = get_primary_peers(upstream_name)
if not peers then
ngx.print("[]")
return
end
peers_backup, err = get_backup_peers(upstream_name)
if peers_backup then
for k, v in pairs(peers_backup) do
table.insert(peers,v)
end
end
ngx.print(json.encode(peers))
}
}
@@ -0,0 +1,5 @@
upstream {$UPSTREAM_NAME}
{
{$NODE_ALGO}
{$NODE_SERVER_LIST}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

+21
View File
@@ -0,0 +1,21 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('op_load_balance');">服务</p>
<p onclick="loadBalanceList();">负载均衡</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript" src="/plugins/file?name=op_load_balance&f=js/app.js"></script>
<script type="text/javascript">
resetPluginWinWidth(800);
resetPluginWinHeight(300);
$.getScript( "/plugins/file?name=op_load_balance&f=js/app.js", function(){
pluginService('op_load_balance');
});
</script>
+474
View File
@@ -0,0 +1,474 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import json
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'op_load_balance'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getArgs():
args = sys.argv[2:]
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 getConf():
path = getServerDir() + "/cfg.json"
if not os.path.exists(path):
mw.writeFile(path, '[]')
c = mw.readFile(path)
return json.loads(c)
def writeConf(data):
path = getServerDir() + "/cfg.json"
mw.writeFile(path, json.dumps(data))
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$APP_PATH}', app_path)
return content
def restartWeb():
mw.opWeb('stop')
mw.opWeb('start')
def loadBalanceConf():
path = mw.getServerDir() + '/web_conf/nginx/vhost/load_balance.conf'
return path
def initDreplace():
dst_conf_tpl = getPluginDir() + '/conf/load_balance.conf'
dst_conf = loadBalanceConf()
if not os.path.exists(dst_conf):
con = mw.readFile(dst_conf_tpl)
mw.writeFile(dst_conf, con)
def status():
if not mw.getWebStatus():
return 'stop'
dst_conf = loadBalanceConf()
if not os.path.exists(dst_conf):
return 'stop'
return 'start'
def start():
initDreplace()
restartWeb()
return 'ok'
def stop():
dst_conf = loadBalanceConf()
os.remove(dst_conf)
deleteLoadBalanceAllCfg()
restartWeb()
return 'ok'
def restart():
restartWeb()
return 'ok'
def reload():
restartWeb()
return 'ok'
def installPreInspection():
check_op = mw.getServerDir() + "/openresty"
if not os.path.exists(check_op):
return "请先安装OpenResty"
return 'ok'
def deleteLoadBalanceAllCfg():
cfg = getConf()
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream'
lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file'
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite'
vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost'
for conf in cfg:
upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf'
if os.path.exists(upstream_file):
os.remove(upstream_file)
lua_file = lua_dir + '/' + conf['upstream_name'] + '.lua'
if os.path.exists(lua_file):
os.remove(lua_file)
rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf'
mw.writeFile(rewrite_file, '')
path = vhost_dir + '/' + conf['domain'] + '.conf'
content = mw.readFile(path)
content = re.sub('include ' + upstream_file + ';' + "\n", '', content)
mw.writeFile(path, content)
mw.opLuaInitWorkerFile()
def makeConfServerList(data):
slist = ''
for x in data:
slist += 'server '
slist += x['ip'] + ':' + x['port']
if x['state'] == '0':
slist += ' down;\n\t'
continue
if x['state'] == '2':
slist += ' backup;\n\t'
continue
slist += ' weight=' + x['weight']
slist += ' max_fails=' + x['max_fails']
slist += ' fail_timeout=' + x['fail_timeout'] + "s;\n\t"
return slist
def makeLoadBalanceAllCfg(row):
# 生成所有配置
cfg = getConf()
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream'
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite'
vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost'
upstream_tpl = getPluginDir() + '/conf/upstream.tpl.conf'
rewrite_tpl = getPluginDir() + '/conf/rewrite.tpl.conf'
if not os.path.exists(upstream_dir):
os.makedirs(upstream_dir)
conf = cfg[row]
# replace vhost start
vhost_file = vhost_dir + '/' + conf['domain'] + '.conf'
vcontent = mw.readFile(vhost_file)
vhost_find_str = 'upstream/' + conf['upstream_name'] + '.conf'
vhead = 'include ' + mw.getServerDir() + '/web_conf/nginx/' + \
vhost_find_str + ';'
vpos = vcontent.find(vhost_find_str)
if vpos < 0:
vcontent = vhead + "\n" + vcontent
mw.writeFile(vhost_file, vcontent)
# replace vhost end
# make upstream start
upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf'
content = ''
if len(conf['node_list']) > 0:
content = mw.readFile(upstream_tpl)
slist = makeConfServerList(conf['node_list'])
content = content.replace('{$NODE_SERVER_LIST}', slist)
content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name'])
if conf['node_algo'] != 'polling':
content = content.replace('{$NODE_ALGO}', conf['node_algo'] + ';')
else:
content = content.replace('{$NODE_ALGO}', '')
mw.writeFile(upstream_file, content)
# make upstream end
# make rewrite start
rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf'
rcontent = ''
if len(conf['node_list']) > 0:
rcontent = mw.readFile(rewrite_tpl)
rcontent = rcontent.replace('{$UPSTREAM_NAME}', conf['upstream_name'])
mw.writeFile(rewrite_file, rcontent)
# make rewrite end
# health check start
lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file'
lua_init_worker_file = lua_dir + '/' + conf['upstream_name'] + '.lua'
if conf['node_health_check'] == 'ok':
lua_dir_tpl = getPluginDir() + '/lua/health_check.lua.tpl'
content = mw.readFile(lua_dir_tpl)
content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name'])
content = content.replace('{$DOMAIN}', conf['domain'])
mw.writeFile(lua_init_worker_file, content)
else:
if os.path.exists(lua_init_worker_file):
os.remove(lua_init_worker_file)
mw.opLuaInitWorkerFile()
# health check end
return True
def add_load_balance(args):
data = checkArgs(
args, ['domain', 'upstream_name', 'node_algo', 'node_list', 'node_health_check'])
if not data[0]:
return data[1]
domain_json = args['domain']
tmp = json.loads(domain_json)
domain = tmp['domain']
cfg = getConf()
cfg_len = len(cfg)
tmp = {}
tmp['domain'] = domain
tmp['data'] = args['domain']
tmp['upstream_name'] = args['upstream_name']
tmp['node_algo'] = args['node_algo']
tmp['node_list'] = args['node_list']
tmp['node_health_check'] = args['node_health_check']
cfg.append(tmp)
writeConf(cfg)
import site_api
sobj = site_api.site_api()
domain_path = mw.getWwwDir() + '/' + domain
ps = '负载均衡[' + domain + ']'
data = sobj.add(domain_json, '80', ps, domain_path, '00')
makeLoadBalanceAllCfg(cfg_len)
mw.restartWeb()
return mw.returnJson(True, '添加成功', data)
def edit_load_balance(args):
data = checkArgs(
args, ['row', 'node_algo', 'node_list', 'node_health_check'])
if not data[0]:
return data[1]
row = int(args['row'])
cfg = getConf()
tmp = cfg[row]
tmp['node_algo'] = args['node_algo']
tmp['node_list'] = args['node_list']
tmp['node_health_check'] = args['node_health_check']
cfg[row] = tmp
writeConf(cfg)
makeLoadBalanceAllCfg(row)
mw.restartWeb()
return mw.returnJson(True, '修改成功', data)
def loadBalanceList():
cfg = getConf()
return mw.returnJson(True, 'ok', cfg)
def loadBalanceDelete():
args = getArgs()
data = checkArgs(args, ['row'])
if not data[0]:
return data[1]
row = int(args['row'])
cfg = getConf()
data = cfg[row]
import site_api
sobj = site_api.site_api()
sid = mw.M('sites').where('name=?', (data['domain'],)).getField('id')
if type(sid) == list:
del(cfg[row])
writeConf(cfg)
return mw.returnJson(False, '已经删除了!')
status = sobj.delete(sid, data['domain'], 1)
status_data = json.loads(status)
if status_data['status']:
del(cfg[row])
writeConf(cfg)
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream'
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite'
upstream_file = upstream_dir + '/' + data['upstream_name'] + '.conf'
if os.path.exists(upstream_file):
os.remove(upstream_file)
rewrite_file = rewrite_dir + '/' + data['domain'] + '.conf'
if os.path.exists(rewrite_file):
mw.writeFile(rewrite_file, '')
return mw.returnJson(status_data['status'], status_data['msg'])
def http_get(url):
ret = re.search(r'https://', url)
if ret:
try:
from gevent import monkey
monkey.patch_ssl()
import requests
ret = requests.get(url=str(url), verify=False, timeout=10)
status = [200, 301, 302, 404, 403]
if ret.status_code in status:
return True
else:
return False
except:
return False
else:
try:
if sys.version_info[0] == 2:
import urllib2
rec = urllib2.urlopen(url, timeout=3)
else:
import urllib.request
rec = urllib.request.urlopen(url, timeout=3)
status = [200, 301, 302, 404, 403]
if rec.getcode() in status:
return True
return False
except:
return False
def checkUrl():
args = getArgs()
data = checkArgs(args, ['ip', 'port', 'path'])
if not data[0]:
return data[1]
ip = args['ip']
port = args['port']
path = args['path']
if port == '443':
url = 'https://' + str(ip) + ':' + str(port) + str(path.strip())
else:
url = 'http://' + str(ip) + ':' + str(port) + str(path.strip())
ret = http_get(url)
if not ret:
return mw.returnJson(False, '访问节点[%s]失败' % url)
return mw.returnJson(True, '访问节点[%s]成功' % url)
def getHealthStatus():
args = getArgs()
data = checkArgs(args, ['row'])
if not data[0]:
return data[1]
row = int(args['row'])
cfg = getConf()
data = cfg[row]
url = 'http://' + data['domain'] + \
'/upstream_status_' + data['upstream_name']
url_data = mw.httpGet(url)
return mw.returnJson(True, 'ok', json.loads(url_data))
def getLogs():
args = getArgs()
data = checkArgs(args, ['domain'])
if not data[0]:
return data[1]
domain = args['domain']
logs = mw.getLogsDir() + '/' + domain + '.log'
return logs
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())
elif func == 'install_pre_inspection':
print(installPreInspection())
elif func == 'add_load_balance':
print(addLoadBalance())
elif func == 'load_balance_list':
print(loadBalanceList())
elif func == 'load_balance_delete':
print(loadBalanceDelete())
elif func == 'check_url':
print(checkUrl())
elif func == 'get_logs':
print(getLogs())
elif func == 'get_health_status':
print(getHealthStatus())
else:
print('error')
+16
View File
@@ -0,0 +1,16 @@
{
"title":"OP负载均衡",
"tip":"soft",
"name":"op_load_balance",
"type":"其他插件",
"install_pre_inspection":true,
"ps":"基于OpenResty的负载均衡",
"shell":"install.sh",
"checks":"server/op_load_balance",
"path":"server/op_load_balance",
"author":"midoks",
"home":"https://github.com/midoks",
"date":"2023-02-02",
"pid": "1",
"versions": ["1.0"]
}
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
action=$1
version=$2
sys_os=`uname`
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
if [ "$sys_os" == "Darwin" ];then
BAK='_bak'
else
BAK=''
fi
Install_App(){
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/op_load_balance
echo "${version}" > $serverPath/op_load_balance/version.pl
cd ${rootPath} && python3 ${rootPath}/plugins/op_load_balance/index.py start
echo 'install ok' > $install_tmp
}
Uninstall_App(){
cd ${rootPath} && python3 ${rootPath}/plugins/op_load_balance/index.py stop
rm -rf $serverPath/op_load_balance
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+606
View File
@@ -0,0 +1,606 @@
function ooPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'op_load_balance', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function ooAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
return syncPost('/plugins/run', {name:'op_load_balance', func:method, args:_args});
}
function ooPostCallbak(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'op_load_balance';
req_data['func'] = method;
args['version'] = '1.0';
if (typeof(args) == 'string'){
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 addNode(){
layer.open({
type: 1,
area: ['450px','580px'],
title: '添加节点',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:['提交','关闭'],
content: "<form class='bt-form pd20'>\
<div class='line'>\
<span class='tname'>IP地址</span>\
<div class='info-r'>\
<input name='ip' class='bt-input-text mr5' placeholder='负载名称,可以是英文字母和下划线,不能使用中文' type='text' style='width:250px' value='127.0.0.1'>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>端口</span>\
<div class='info-r'>\
<input name='port' class='bt-input-text mr5' type='text' style='width:250px' value='80'>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>验证文件路径</span>\
<div class='info-r'>\
<input name='path' class='bt-input-text mr5' type='text' style='width:250px' value='/'>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点状态</span>\
<div class='info-r'>\
<select name='state'>\
<option value='1'>参与者</option>\
<option value='2'>备份</option>\
<option value='0'>停用</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>权重</span>\
<div class='info-r'>\
<input name='weight' class='bt-input-text mr5' type='text' style='width:250px' value='1'>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>阈值</span>\
<div class='info-r'>\
<input name='max_fails' class='bt-input-text mr5' type='text' style='width:250px' value='2'>次\
</div>\
</div>\
<div class='line'>\
<span class='tname'>恢复时间</span>\
<div class='info-r'>\
<input name='fail_timeout' class='bt-input-text mr5' type='text' style='width:250px' value='10'>秒\
</div>\
</div>\
<ul style='margin-left:10px' class='help-info-text c7'>\
<li>备份状态: 指当其它节点都无法使用时才会使用此节点</li>\
<li>参与状态: 正常参与负载均衡,请至少添加1个普通节点</li>\
<li>验证文件路径: 用于检查文件路径地址是否可用</li>\
<li>IP地址: 仅支持IP地址,否则无法正常参与负载均衡</li>\
<li>阈值: 在恢复时间的时间段内,如果OpenResty与节点通信尝试失败的次数达到此值,OpenResty就认为服务器不可用</li>\
</ul>\
</form>",
success:function(){
},
yes:function(index) {
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var path = $('input[name="path"]').val();
var state = $('select[name="state"]').val();
var weight = $('input[name="weight"]').val();
var max_fails = $('input[name="max_fails"]').val();
var fail_timeout = $('input[name="fail_timeout"]').val();
ooPost('check_url', {ip:ip,port:port,path:path},function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
if (rdata.status){
layer.close(index);
$('#nodecon .nulltr').hide();
var tbody = '<tr>';
tbody +='<td>'+ip+'</td>';
tbody +='<td>'+port+'</td>';
tbody +='<td>'+path+'</td>';
tbody +="<td><select name='state'>";
var state_option_list = {
'1':'参与者',
'2':'备份',
'0':'停用',
}
for (i in state_option_list) {
if (i == state){
tbody +="<option value='"+i+"' selected>"+state_option_list[i]+"</option>";
} else{
tbody +="<option value='"+i+"'>"+state_option_list[i]+"</option>";
}
}
tbody +="</select></td>";
tbody +='<td><input type="number" name="weight" value="'+weight+'" style="width:50px"></td>';
tbody +='<td><input type="number" name="max_fails" value="'+max_fails+'" style="width:50px"></td>';
tbody +='<td><input type="number" name="fail_timeout" value="'+fail_timeout+'" style="width:50px"></td>';
tbody +='<td class="text-right" width="50"><a class="btlink minus delete">删除</a></td>';
tbody += '</tr>';
$('#nodecon').append(tbody);
$('#nodecon .delete').click(function(){
$(this).parent().parent().remove();
if ($('#nodecon tr').length == 1 ){
$('#nodecon .nulltr').show();
}
});
}
},{ icon: rdata.status ? 1 : 2 }, 2000);
});
}
});
}
function addBalance(){
layer.open({
type: 1,
area: ['750px','460px'],
title: '创建负载',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:['提交','关闭'],
content: "<form class='bt-form pd20'>\
<div class='line'>\
<span class='tname'>域名</span>\
<div class='info-r'><textarea name='load_domain' class='bt-input-text mr5' placeholder='' style='width:95%;resize: none;height:90px;line-height:20px;'></textarea></div>\
</div>\
<div class='line'>\
<span class='tname'>负载名称</span>\
<div class='info-r'>\
<input name='upstream_name' class='bt-input-text mr5' placeholder='负载名称,可以是英文字母和下划线,不能使用中文' type='text' style='width:95%' value=''>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点调度</span>\
<div class='info-r'>\
<select name='node_algo'>\
<option value='polling'>轮询[默认]</option>\
<option value='ip_hash'>ip_hash</option>\
<option value='fair'>fair</option>\
<option value='url_hash'>url_hash</option>\
<option value='least_conn'>least_conn</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点健康检查</span>\
<div class='info-r'>\
<input type='checkbox' name='node_health_check' checked>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点</span>\
<div class='info-r'>\
<div class='table-con divtable' style='max-height:120px;overflow:auto; margin-bottom:8px;width:95%'>\
<table class='table table-hover' id='fixTable3'>\
<thead>\
<tr>\
<th width='120'>IP地址</th>\
<th width='60'>端口</th>\
<th width='120'>验证路径</th>\
<th width='60'>状态</th>\
<th width='60'>权重</th>\
<th width='60'>阀值</th>\
<th width='120'>恢复时间</th>\
<th width='80' class='text-right'>操作</th>\
</tr>\
</thead>\
<tbody id='nodecon'>\
<tr class='nulltr'>\
<td colspan='8' align='center'>当前节点为空,请至少添加一个普通节点</td>\
</tr>\
</tbody>\
</table>\
</div>\
<span class='btn btn-success btn-sm add_node' style='vertical-align:0'>添加节点</span>\
</div>\
</div>\
</form>",
success:function(){
$('textarea[name="load_domain"]').attr('placeholder','每行填写一个域名,默认为80端口。\n泛解析添加方法 *.domain.com\n如另加端口格式为 www.domain.com:88');
var rval = getRandomString(6);
$('input[name="upstream_name"]').val('load_balance_'+rval);
$('.add_node').click(function(){
addNode();
});
},
yes:function(index) {
var data = {};
var upstream_name = $('input[name="upstream_name"]').val();
if (upstream_name == ''){
layer.msg('负载名称不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var domain = $('textarea[name="load_domain"]').val().replace('http://','').replace('https://','').split("\n");
if (domain[0] == ''){
layer.msg('域名不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var domainlist = '';
for(var i=1; i<domain.length; i++){
domainlist += '"'+domain[i]+'",';
}
domain ='{"domain":"'+domain[0]+'","domainlist":['+domainlist+'],"count":'+domain.length+'}';//拼接json
data['domain'] = domain;
data['upstream_name'] = upstream_name;
data['node_algo'] = $('select[name="node_algo"]').val();
data['node_health_check'] = 'fail';
if ($('input[name="node_health_check"]').prop('checked')){
data['node_health_check'] = 'ok';
}
var node_list = [];
$('#nodecon tr').each(function(){
var ip = $(this).find('td').eq(0).text();
var port = $(this).find('td').eq(1).text();
if (port == ''){return;}
var path = $(this).find('td').eq(2).text();
var state = $(this).find('select[name="state"]').val();
var weight = $(this).find('input[name="weight"]').val();
var max_fails = $(this).find('input[name="max_fails"]').val();
var fail_timeout = $(this).find('input[name="fail_timeout"]').val();
var tmp = {
ip:ip,
port:port,
path:path,
state:state,
weight:weight,
max_fails:max_fails,
fail_timeout:fail_timeout,
}
node_list.push(tmp);
});
data['node_list'] = node_list;
ooPostCallbak('add_load_balance', data, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
layer.close(index);
loadBalanceListRender();
},{ icon: rdata.status ? 1 : 2 }, 2000);
});
}
});
}
function editBalance(data, row){
layer.open({
type: 1,
area: ['750px','400px'],
title: '编辑负载',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:['提交','关闭'],
content: "<form class='bt-form pd20'>\
<div class='line'>\
<span class='tname'>负载名称</span>\
<div class='info-r'><input name='upstream_name' class='bt-input-text mr5' type='text' style='width:95%;background: rgb(238, 238, 238);' value='' readonly></div>\
</div>\
<div class='line'>\
<span class='tname'>节点调度</span>\
<div class='info-r'>\
<select name='node_algo'>\
<option value='polling'>轮询[默认]</option>\
<option value='ip_hash'>ip_hash</option>\
<option value='fair'>fair</option>\
<option value='url_hash'>url_hash</option>\
<option value='least_conn'>least_conn</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点健康检查</span>\
<div class='info-r'>\
<input type='checkbox' name='node_health_check'>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>节点</span>\
<div class='info-r'>\
<div class='table-con divtable' style='max-height:120px;overflow:auto; margin-bottom:8px;width:95%'>\
<table class='table table-hover' id='fixTable3'>\
<thead>\
<tr>\
<th width='120'>IP地址</th>\
<th width='60'>端口</th>\
<th width='120'>验证路径</th>\
<th width='60'>状态</th>\
<th width='60'>权重</th>\
<th width='60'>阀值</th>\
<th width='120'>恢复时间</th>\
<th width='80' class='text-right'>操作</th>\
</tr>\
</thead>\
<tbody id='nodecon'>\
<tr class='nulltr'>\
<td colspan='8' align='center'>当前节点为空,请至少添加一个普通节点</td>\
</tr>\
</tbody>\
</table>\
</div>\
<span class='btn btn-success btn-sm add_node' style='vertical-align:0'>添加节点</span>\
</div>\
</div>\
</form>",
success:function(){
$('input[name="upstream_name"]').val(data['upstream_name']);
$('select[name="node_algo"]').val(data['node_algo']);
$('input[name="node_health_check"]').prop('checked',false);
if (data['node_health_check'] == 'ok'){
$('input[name="node_health_check"]').prop('checked',true);
}
var node_list = data['node_list'];
if (node_list.length>0){
$('#nodecon .nulltr').hide();
}
var state_option_list = {
'1':'参与者',
'2':'备份',
'0':'停用',
}
for (var n in node_list) {
var tbody = '<tr>';
tbody +='<td>'+node_list[n]['ip']+'</td>';
tbody +='<td>'+node_list[n]['port']+'</td>';
tbody +='<td>'+node_list[n]['path']+'</td>';
tbody +="<td><select name='state'>";
for (i in state_option_list) {
if (i == node_list[n]['state']){
tbody +="<option value='"+i+"' selected>"+state_option_list[i]+"</option>";
} else{
tbody +="<option value='"+i+"'>"+state_option_list[i]+"</option>";
}
}
tbody +="</select></td>";
tbody +='<td><input type="number" name="weight" value="'+node_list[n]['weight']+'" style="width:50px"></td>';
tbody +='<td><input type="number" name="max_fails" value="'+node_list[n]['max_fails']+'" style="width:50px"></td>';
tbody +='<td><input type="number" name="fail_timeout" value="'+node_list[n]['fail_timeout']+'" style="width:50px"></td>';
tbody +='<td class="text-right" width="50"><a class="btlink minus delete">删除</a></td>';
tbody += '</tr>';
$('#nodecon').append(tbody);
}
$('#nodecon .delete').click(function(){
$(this).parent().parent().remove();
if ($('#nodecon tr').length == 1 ){
$('#nodecon .nulltr').show();
}
});
$('.add_node').click(function(){
addNode();
});
},
yes:function(index) {
var data = {};
data['node_algo'] = $('select[name="node_algo"]').val();
data['node_health_check'] = 'fail';
if ($('input[name="node_health_check"]').prop('checked')){
data['node_health_check'] = 'ok';
}
var node_list = [];
$('#nodecon tr').each(function(){
var ip = $(this).find('td').eq(0).text();
var port = $(this).find('td').eq(1).text();
if (port == ''){return;}
var path = $(this).find('td').eq(2).text();
var state = $(this).find('select[name="state"]').val();
var weight = $(this).find('input[name="weight"]').val();
var max_fails = $(this).find('input[name="max_fails"]').val();
var fail_timeout = $(this).find('input[name="fail_timeout"]').val();
var tmp = {
ip:ip,
port:port,
path:path,
state:state,
weight:weight,
max_fails:max_fails,
fail_timeout:fail_timeout,
}
node_list.push(tmp);
});
data['node_list'] = node_list;
data['row'] = row;
ooPostCallbak('edit_load_balance', data, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
layer.close(index);
loadBalanceListRender();
},{ icon: rdata.status ? 1 : 2 }, 2000);
});
}
});
}
function loadBalanceListRender(){
ooPost('load_balance_list', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var alist = rdata.data;
var tbody = '';
for (var i = 0; i < alist.length; i++) {
tbody += '<tr>';
tbody += '<td>'+alist[i]['domain']+'</td>';
tbody += '<td>'+alist[i]['upstream_name']+'</td>';
tbody += '<td>'+alist[i]['node_list'].length+'</td>';
tbody += '<td><a class="btlink log_look" data-row="'+i+'">查看</a></td>';
tbody += '<td><a class="btlink health_status" data-row="'+i+'">查看</a></td>';
tbody += '<td style="text-align: right;"><a class="btlink edit" data-row="'+i+'">修改</a> | <a class="btlink delete" data-row="'+i+'">删除</a></td>';
tbody += '</tr>';
}
$('#nodeTable').html(tbody);
$('.nodeTablePage .Pcount').text('共'+alist.length+'条');
$('#nodeTable .edit').click(function(){
var row = $(this).data('row');
editBalance(alist[row],row);
});
$('#nodeTable .log_look').click(function(){
var row = $(this).data('row');
var args = {'domain':alist[row]['domain']};
pluginRollingLogs('op_load_balance','','get_logs',JSON.stringify(args),20);
});
$('#nodeTable .health_status').click(function(){
var row = $(this).data('row');
ooPost('get_health_status', {row:row}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var tval = '';
for (var i = 0; i < rdata.data.length; i++) {
tval += '<tr>';
tval += '<td>'+rdata.data[i]['name']+'</td>';
if (typeof(rdata.data[i]['down']) != 'undefined' && rdata.data[i]['down']){
tval += '<td><span style="color:red;">不正常</span></td>';
} else{
tval += '<td><span class="btlink">正常</span></td>';
}
tval += '</tr>';
}
var tbody = "<div class='bt-form pd20'>\
<div>\
<div id='gitea_table' class='divtable' style='margin-top:5px;'>\
<table class='table table-hover'>\
<thead>\
<tr>\
<th width='120'>地址</th>\
<th width='60'>状态</th>\
</tr>\
</thead>\
<tbody>"+tval+"</tbody>\
</table>\
</div>\
</div>\
</div>";
layer.open({
type: 1,
area: ['500px','300px'],
title: '节点状态',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:['提交','关闭'],
content:tbody,
});
});
});
$('#nodeTable .delete').click(function(){
var row = $(this).data('row');
ooPost('load_balance_delete', {row:row}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
loadBalanceListRender();
},{ icon: rdata.status ? 1 : 2 }, 2000);
});
});
});
}
function loadBalanceList() {
var body = '<div class="bt-box active" style="display: block;">\
<div class="mb10">\
<button class="btn btn-success btn-sm" data-index="0" onclick="addBalance()">添加负载</button>\
<div class="divtable mt10">\
<table class="table table-hover">\
<thead>\
<tr>\
<th>网站</th>\
<th>负载名称</th>\
<th>节点</th>\
<th>日志</th>\
<th>状态</th>\
<th width="100" style="text-align: right;">操作</th>\
</tr>\
</thead>\
<tbody id="nodeTable"></tbody>\
</table>\
<div class="nodeTablePage page" data-type="nodePage">\
<div><span class="Pcount">共0条</span></div>\
</div>\
</div>\
</div>\
</div>\
</div>';
$(".soft-man-con").html(body);
loadBalanceListRender();
}
@@ -0,0 +1,18 @@
local hc = require "resty.upstream.healthcheck"
local ok, err = hc.spawn_checker {
shm = "healthcheck",
type = "http",
upstream = "{$UPSTREAM_NAME}",
http_req = "GET / HTTP/1.0\r\nHost: {$UPSTREAM_NAME}\r\n\r\n",
interval = 2000,
timeout = 6000,
fall = 3,
rise = 2,
valid_statuses = {200, 302},
concurrency = 20,
}
if not ok then
ngx.log(ngx.ERR, "=======> load balance health checker error: ", err)
return
end
+53 -53
View File
@@ -225,6 +225,7 @@ def initTotalInfo():
_name[name] = tmp
total_contents['sites'] = _name
total_contents['start_time'] = str(time.time())
cjson = mw.getJson(total_contents)
mw.writeFile(path_total, cjson)
@@ -324,8 +325,41 @@ def restartWeb():
mw.opWeb('start')
def initDreplace():
def makeDstLua():
root_init_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_by_lua_file'
root_worker_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file'
root_access_dir = mw.getServerDir() + '/web_conf/nginx/lua/access_by_lua_file'
path = getServerDir()
path_tpl = getPluginDir()
waf_common_tpl = path_tpl + "/waf/lua/waf_common.lua"
waf_common_dst = path + "/waf/lua/waf_common.lua"
content = mw.readFile(waf_common_tpl)
content = contentReplace(content)
mw.writeFile(waf_common_dst, content)
waf_init_tpl = path_tpl + "/waf/lua/init_preload.lua"
waf_init_dst = root_init_dir + "/waf_init_preload.lua"
content = mw.readFile(waf_init_tpl)
content = contentReplace(content)
mw.writeFile(waf_init_dst, content)
init_worker_tpl = path_tpl + "/waf/lua/init_worker.lua"
init_worker_dst = root_worker_dir + '/opwaf_init_worker.lua'
content = mw.readFile(init_worker_tpl)
content = contentReplace(content)
mw.writeFile(init_worker_dst, content)
access_file_tpl = path_tpl + "/waf/lua/init.lua"
access_file_dst = root_access_dir + '/opwaf_init.lua'
content = mw.readFile(access_file_tpl)
content = contentReplace(content)
mw.writeFile(access_file_dst, content)
mw.opLuaMakeAll()
def initDreplace():
path = getServerDir()
if not os.path.exists(path + '/waf/lua'):
sdir = getPluginDir() + '/waf'
@@ -348,20 +382,7 @@ def initDreplace():
content['reqfile_path'] = wfDir
mw.writeFile(config, mw.getJson(content))
config = path + "/waf/lua/init.lua"
content = mw.readFile(config)
content = contentReplace(content)
mw.writeFile(config, content)
config_common = path + "/waf/lua/common.lua"
content = mw.readFile(config_common)
content = contentReplace(content)
mw.writeFile(config_common, content)
init_worker = path + "/waf/lua/init_worker.lua"
content = mw.readFile(init_worker)
content = contentReplace(content)
mw.writeFile(init_worker, content)
makeDstLua()
waf_conf = dstWafConf()
if not os.path.exists(waf_conf):
@@ -396,16 +417,6 @@ def status():
def start():
initDreplace()
path = mw.getServerDir() + '/web_conf/nginx/lua/lua.conf'
init_worker_lua = getServerDir() + '/waf/lua/init_worker.lua'
init_lua = getServerDir() + '/waf/lua/init.lua'
conf = mw.readFile(path)
conf = re.sub('init_worker_by_lua_file (.*);',
"init_worker_by_lua_file " + init_worker_lua + ";", conf)
conf = re.sub('access_by_lua_file (.*);',
"access_by_lua_file " + init_lua + ";", conf)
mw.writeFile(path, conf)
import tool_task
tool_task.createBgTask()
@@ -414,15 +425,21 @@ def start():
def stop():
root_init_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_by_lua_file'
root_worker_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file'
root_access_dir = mw.getServerDir() + '/web_conf/nginx/lua/access_by_lua_file'
path = mw.getServerDir() + '/web_conf/nginx/lua/lua.conf'
empty_lua = mw.getServerDir() + '/web_conf/nginx/lua/empty.lua'
conf = mw.readFile(path)
conf = re.sub('init_worker_by_lua_file (.*);',
"init_worker_by_lua_file " + empty_lua + ";", conf)
conf = re.sub('access_by_lua_file (.*);',
"access_by_lua_file " + empty_lua + ";", conf)
mw.writeFile(path, conf)
waf_init_dst = root_init_dir + "/waf_init_preload.lua"
if os.path.exists(waf_init_dst):
os.remove(waf_init_dst)
init_worker_dst = root_worker_dir + '/opwaf_init_worker.lua'
if os.path.exists(init_worker_dst):
os.remove(init_worker_dst)
access_file_dst = root_access_dir + '/opwaf_init.lua'
if os.path.exists(access_file_dst):
os.remove(access_file_dst)
wafconf = dstWafConf()
if os.path.exists(wafconf):
@@ -431,6 +448,8 @@ def stop():
import tool_task
tool_task.removeBgTask()
mw.opLuaMakeAll()
restartWeb()
return 'ok'
@@ -443,26 +462,7 @@ def restart():
def reload():
stop()
path = getServerDir()
path_tpl = getPluginDir()
config = path + "/waf/lua/common.lua"
config_tpl = path_tpl + "/waf/lua/common.lua"
content = mw.readFile(config_tpl)
content = contentReplace(content)
mw.writeFile(config, content)
config = path + "/waf/lua/init_worker.lua"
config_tpl = path_tpl + "/waf/lua/init_worker.lua"
content = mw.readFile(config_tpl)
content = contentReplace(content)
mw.writeFile(config, content)
config = path + "/waf/lua/init.lua"
config_tpl = path_tpl + "/waf/lua/init.lua"
content = mw.readFile(config_tpl)
content = contentReplace(content)
mw.writeFile(config, content)
makeDstLua()
errlog = mw.getServerDir() + "/openresty/nginx/logs/error.log"
mw.execShell('rm -rf ' + errlog)
+13 -1
View File
@@ -1,4 +1,16 @@
{
"hook":[
{
"tag":"site_cb",
"site_cb": {
"title":"网站统计",
"name":"op_waf",
"add":{"func":"reload"},
"update":{"func":"reload"},
"delete":{"func":"reload"}
}
}
],
"title":"OP防火墙",
"tip":"soft",
"name":"op_waf",
@@ -12,5 +24,5 @@
"home":"https://github.com/loveshell/ngx_lua_waf",
"date":"2019-04-21",
"pid": "1",
"versions": ["0.2.4"]
"versions": ["0.2.6"]
}
+7 -8
View File
@@ -24,7 +24,7 @@ else
fi
Install_of(){
Install_App(){
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source/op_waf
@@ -41,7 +41,9 @@ Install_of(){
cd $serverPath/source/op_waf && tar xvf luarocks-3.5.0.tar.gz
# cd luarocks-3.9.1 && ./configure && make bootstrap
cd luarocks-3.5.0 && ./configure --prefix=$serverPath/op_waf/luarocks --with-lua-include=$serverPath/openresty/luajit/include/luajit-2.1 --with-lua-bin=$serverPath/openresty/luajit/bin
cd luarocks-3.5.0 && ./configure --prefix=$serverPath/op_waf/luarocks \
--with-lua-include=$serverPath/openresty/luajit/include/luajit-2.1 \
--with-lua-bin=$serverPath/openresty/luajit/bin
make -I${serverPath}/openresty/luajit/bin
make install
fi
@@ -85,13 +87,10 @@ Install_of(){
echo 'install ok' > $install_tmp
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py start
# cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py restart
}
Uninstall_of(){
Uninstall_App(){
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py stop
if [ "$?" == "0" ];then
@@ -102,7 +101,7 @@ Uninstall_of(){
action=$1
if [ "${1}" == 'install' ];then
Install_of
Install_App
else
Uninstall_of
Uninstall_App
fi
+5 -1
View File
@@ -961,8 +961,12 @@ function wafScreen(){
owPost('waf_srceen', {}, function(data){
var rdata = $.parseJSON(data.data);
var end_time = Date.now();
var cos_time = (end_time/1000) - parseInt(rdata['start_time']);
var cos_day = parseInt(parseInt(cos_time)/86400);
var con = '<div class="wavbox alert alert-success" style="margin-right:16px">总拦截<span>'+rdata.total+'</span>次</div>';
con += '<div class="wavbox alert alert-info" style="margin-right:16px">安全防护<span>0</span>天</div>';
con += '<div class="wavbox alert alert-info" style="margin-right:16px">安全防护<span>'+cos_day+'</span>天</div>';
con += '<div class="screen">\
<div class="line"><span class="name">POST渗透</span><span class="val">'+rdata.rules.post+'</span></div>\
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
DST_DIR=/www/server/op_waf
DIS_FILE=${DST_DIR}/cpu.info
CPU_USAGE=`top -bn 1 | fgrep 'Cpu(s)' | awk '{print 100 -$8}' | awk -F . '{print $1}'`
echo $CPU_USAGE
echo $CPU_USAGE > $DIS_FILE
echo "done success!"
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
DST_DIR=/www/server/op_waf
DIS_FILE=${DST_DIR}/cpu.info
function GetCpuUsage(){
cpu_info=`cat /proc/stat | head -n 1`
idle_cpu=`echo $cpu_info|awk '{print $2}'`
cpu_total_time=0
for ci in ${cpu_info[@]}; do
if [ "$ci" == "cpu" ];then
continue
else
#echo $ci
cpu_total_time=`expr $cpu_total_time + $ci`
fi
done
#echo "idle_cpu:${idle_cpu}"
#echo "cpu_total_time:${cpu_total_time}"
cpu_percet=$(awk "BEGIN{print ((${cpu_total_time}-${idle_cpu})/${cpu_total_time})*100}")
echo "${cpu_percet}"
return 0
}
# one value detal
getOne=`GetCpuUsage`
CPU_USAGE=`echo $getOne | awk -F . '{print $1}'`
echo "cpu usage:${CPU_USAGE}"
echo $CPU_USAGE > $DIS_FILE
echo "done success!"
# two value compare
# getOne=`GetCpuUsage`
# echo "getOne:$getOne"
# sleep 1
# getTwo=`GetCpuUsage`
# echo "getTwo:$getTwo"
# cpu_percet_calc=$(awk "BEGIN{print (${getOne}+${getTwo})/2}")
# echo "cpu_percet_calc:${cpu_percet_calc}"
# #echo '0.61212' | awk -F . '{print $1}'
# CPU_USAGE=`echo $cpu_percet_calc | awk -F . '{print $1}'`
# echo "cpu usage:${CPU_USAGE}"
# echo $CPU_USAGE > $DIS_FILE
# echo "done success!"
+2 -1
View File
@@ -26,4 +26,5 @@ fi
# $RUN_CMD --stap --shdict 'limit 10m' test_find_server_name.lua
# $RUN_CMD test_rand.lua
$RUN_CMD test_ffi_time.lua
# $RUN_CMD test_ffi_time.lua
$RUN_CMD test_get_cpu.lua
+69
View File
@@ -0,0 +1,69 @@
-- cd /www/server/mdserver-web/plugins/op_waf/t/bench && bash bench.sh
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
local function file_exists(path)
local file = io.open(path, "rb")
if file then file:close() end
return file ~= nil
end
-- 以上为预热操作
collectgarbage()
local json = require "cjson"
local ngx_re = require "ngx.re"
local function data_split(self, str,reps )
local rsList = {}
string.gsub(str,'[^'..reps..']+',function(w)
table.insert(rsList,w)
end)
return rsList
end
local function get_cpu_stat()
local cpu_total = 0
local fp = io.open('/proc/stat','r')
local cpu_line = fp:read()
fp:close()
local list = ngx_re.split(cpu_line," ")
table.remove(list,1)
table.remove(list,1)
local idie = list[4]
for i,v in pairs(list)
do
cpu_total = cpu_total + v
end
local use_percent = tonumber(100-(idie/cpu_total)*100)
return cpu_total,idie,use_percent
end
local function get_cpu_percent()
local cpu_total,idie,use_percent = get_cpu_stat()
ngx.sleep(2)
local cpu_total2,idie2,use_percent2 = get_cpu_stat()
local cpu_usage_percent = tonumber(100-(((idie2-idie)/(cpu_total2-cpu_total))*100))
ngx.say("cpu_usage_percent:"..cpu_usage_percent)
return cpu_usage_percent
end
ngx.update_time()
local begin = ngx.now()
local N = 1e1
for i = 1, N do
get_cpu_stat()
end
ngx.update_time()
ngx.say("test_get_cpu elapsed: ", (ngx.now() - begin))
+86 -20
View File
@@ -1,6 +1,46 @@
#!/bin/sh
export PATH=$PATH:/opt/stap/bin:/opt/stapxx
# cd /www/server/mdserver-web/plugins/op_waf/t && bash ngx_debug.sh lua ok
# cd /www/server/mdserver-web/plugins/op_waf/t && bash ngx_debug.sh c ok
if [ ${_os} == "Darwin" ]; then
OSNAME='macos'
elif grep -Eq "openSUSE" /etc/*-release; then
OSNAME='opensuse'
zypper refresh
zypper install cron wget curl zip unzip
elif grep -Eq "FreeBSD" /etc/*-release; then
OSNAME='freebsd'
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Fedora" /etc/issue || grep -Eq "Fedora" /etc/*-release; then
OSNAME='fedora'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Rocky" /etc/issue || grep -Eq "Rocky" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "AlmaLinux" /etc/issue || grep -Eq "AlmaLinux" /etc/*-release; then
OSNAME='rhel'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Amazon Linux" /etc/issue || grep -Eq "Amazon Linux" /etc/*-release; then
OSNAME='amazon'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "Debian" /etc/issue || grep -Eq "Debian" /etc/os-release; then
OSNAME='debian'
apt update -y
apt install -y wget curl zip unzip tar cron
elif grep -Eqi "Ubuntu" /etc/issue || grep -Eq "Ubuntu" /etc/os-release; then
OSNAME='ubuntu'
apt update -y
apt install -y wget curl zip unzip tar cron
else
OSNAME='unknow'
fi
# https://moonbingbing.gitbooks.io/openresty-best-practices/content/flame_graph/install.html
# apt install elfutils
# sudo apt-get install -y systemtap gcc
@@ -23,7 +63,7 @@ then
exit
fi
pid=`ps -ef|grep openresty | grep -v grep | awk '{print $2}'`
pids=`ps -ef|grep nginx | grep -v grep | awk '{print $2}'`
name=$2
@@ -33,7 +73,13 @@ name=$2
# apt install -y kernel-debuginfo-common kernel-debuginfo
# apt install -y kernel-*
if [ "$OSNAME" == "debian" ];then
apt install -y systemtap
apt-get install -y build-essential
apt-get install -y linux-headers-$(uname -r)
elif [ "$OSNAME" == "centos" ];then
yum install -y kernel-devel-$(uname -r)
fi
# /opt/stapxx/samples/lj-lua-stacks.sxx --arg time=5 --skip-badvars -x 45266 > tmp.bt
@@ -58,25 +104,45 @@ if [ ! -d /opt/FlameGraph ];then
cd /opt && git clone https://github.com/brendangregg/FlameGraph
fi
if [ $1 == "lua" ]; then
# /opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p 377452 --luajit20 -t 30 >temp.bt
/opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p $pid --luajit20 -t 30 >temp.bt
# /opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >t1.bt
/opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >${name}.bt
elif [ $1 == "c" ]; then
# /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 10 -u > t2.bt
/opt/openresty-systemtap-toolkit/sample-bt -p $pid -t 10 -u > ${name}.bt
else
echo "type is only lua/c"
exit
fi
for pid in ${pids[@]}; do
echo "strace:$pid"
if [ $1 == "lua" ]; then
# --without-luajit-gc64 | lua 模式编译时需要使用此参数
/opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p $pid --luajit20 -t 30 >temp.bt
/opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >${name}_${pid}.bt
elif [ $1 == "c" ]; then
/opt/openresty-systemtap-toolkit/sample-bt -p $pid -t 10 -u > ${name}_${pid}.bt
else
echo "type is only lua/c"
exit
fi
/opt/FlameGraph/stackcollapse-stap.pl ${name}_${pid}.bt >${name}_${pid}.cbt
/opt/FlameGraph/flamegraph.pl ${name}_${pid}.cbt >${name}_${pid}.svg
rm -f temp.bt ${name}_${pid}.bt ${name}_${pid}.cbt
echo "strace:$pid, end!"
echo "${name}_${pid}.svg -- make ok"
done
# if [ $1 == "lua" ]; then
# # /opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p 377452 --luajit20 -t 30 >temp.bt
# /opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p $pid --luajit20 -t 30 >temp.bt
# # /opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >t1.bt
# /opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >${name}.bt
# elif [ $1 == "c" ]; then
# # /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 10 -u > t2.bt
# /opt/openresty-systemtap-toolkit/sample-bt -p $pid -t 10 -u > ${name}.bt
# else
# echo "type is only lua/c"
# exit
# fi
# # debuginfo-install kernel-3.10.0-1160.80.1.el7.x86_64
# # /opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
# # /opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
# /opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
# /opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
/opt/FlameGraph/stackcollapse-stap.pl ${name}.bt >${name}.cbt
/opt/FlameGraph/flamegraph.pl ${name}.cbt >${name}.svg
rm -f temp.bt ${name}.bt ${name}.cbt
# /opt/FlameGraph/stackcollapse-stap.pl ${name}.bt >${name}.cbt
# /opt/FlameGraph/flamegraph.pl ${name}.cbt >${name}.svg
# rm -f temp.bt ${name}.bt ${name}.cbt
+22 -6
View File
@@ -54,7 +54,9 @@ def createBgTask():
"period": "minute-n",
"minute-n": "1",
}
createBgTaskByName(getPluginName(), args)
if mw.isAppleSystem():
createBgTaskByName(getPluginName(), args)
def createBgTaskByName(name, args):
@@ -97,8 +99,14 @@ logs_file=$plugin_path/${rname}.log
''' % (mw_dir, name, getServerDir(), getPluginDir())
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
cmd += 'echo "cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
cmd += 'cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
if mw.isAppleSystem():
cmd += 'echo "cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
cmd += 'cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
else:
cmd += 'echo "cd $mw_dir && source bin/activate && bash $script_path/shell/cpu_usage_file.sh >> $logs_file 2>&1"' + "\n"
cmd += 'cd $mw_dir && source bin/activate && bash $script_path/shell/cpu_usage.sh >> $logs_file 2>&1' + "\n"
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
@@ -128,6 +136,9 @@ logs_file=$plugin_path/${rname}.log
def removeBgTask():
if not mw.isAppleSystem():
return False
cfg_list = getConfigData()
for x in range(len(cfg_list)):
cfg = cfg_list[x]
@@ -147,10 +158,15 @@ def removeBgTask():
def getCpuUsed():
import psutil
used = psutil.cpu_percent(interval=1)
path = getServerDir() + "/cpu.info"
mw.writeFile(path, str(int(used)))
if mw.isAppleSystem():
import psutil
used = psutil.cpu_percent(interval=1)
mw.writeFile(path, str(int(used)))
else:
cmd = "top -bn 1 | fgrep 'Cpu(s)' | awk '{print 100 -$8}' | awk -F . '{print $1}'"
data = mw.execShell(cmd)
mw.writeFile(path, str(int(data[0].strip())))
def run():
+61 -43
View File
@@ -1,19 +1,8 @@
local waf_root = "{$WAF_ROOT}"
local waf_cpath = waf_root.."/waf/lua/?.lua;"..waf_root.."/waf/conf/?.lua;"..waf_root.."/waf/html/?.lua;"
local waf_sopath = waf_root.."/waf/conf/?.so;"
if not package.path:find(waf_cpath) then
package.path = waf_cpath .. package.path
end
if not package.cpath:find(waf_sopath) then
package.cpath = waf_sopath .. package.cpath
end
local json = require "cjson"
local ngx_match = ngx.re.find
local __WAF = require "common"
local __WAF = require "waf_common"
-- print(json.encode(__C))
local C = __WAF:getInstance()
@@ -47,7 +36,8 @@ local url_rules = require "rule_url"
local url_white_rules = require "rule_url_white"
local server_name = string.gsub(C:get_sn(config_domains),'_','.')
-- local server_name = string.gsub(C:get_sn(config_domains),'_','.')
local server_name = C:get_sn(config_domains)
local function initParams()
local data = {}
@@ -354,13 +344,22 @@ local function waf_cc_increase()
local make_uri = "/"..make_uri_str
if params['uri_request_args']['token'] then
ngx.header.content_type = "application/json"
local args_token = params['uri_request_args']['token']
if args_token == make_token then
ngx.shared.waf_limit:set(cache_token, 1, config['safe_verify']['time'])
ngx.shared.waf_limit:set(cache_token, 1, tonumber(config['safe_verify']['time']))
local data = get_return_state(0, "ok")
ngx.say(json.encode(data))
ngx.exit(200)
end
-- C:D("debug[args]:"..tostring(params['uri_request_args']['debug']))
-- if params['uri_request_args']['debug'] == 'ok' then
-- ngx.header.content_type = "application/json"
-- local data = get_return_state(0, "ok")
-- ngx.say(json.encode(data))
-- ngx.exit(200)
-- end
end
local cc_html = ngx.re.gsub(cc_safe_js_html, "{uri}", make_uri_str)
@@ -533,41 +532,60 @@ end
function waf()
min_route()
-- white ip
if waf_ip_white() then return true end
-- url white
if waf_url_white() then return true end
-- black ip
if waf_ip_black() then return true end
-- 封禁ip返回
if waf_drop_ip() then return true end
-- ua check
if waf_user_agent() then return true end
if waf_url() then return true end
-- cc setting
if waf_cc_increase() then return true end
if waf_cc() then return true end
-- cookie检查
if waf_cookie() then return true end
-- C:D("min_route")
-- args参数拦截
if waf_get_args() then return true end
-- 扫描软件禁止
if waf_scan_black() then return true end
if waf_post() then return true end
if site_config[server_name] and site_config[server_name]['open'] then
-- white ip
if waf_ip_white() then return true end
-- C:D("waf_ip_white")
-- url white
if waf_url_white() then return true end
-- C:D("waf_url_white")
-- black ip
if waf_ip_black() then return true end
-- C:D("waf_ip_black")
-- 封禁ip返回
if waf_drop_ip() then return true end
-- C:D("waf_drop_ip")
-- ua check
if waf_user_agent() then return true end
-- C:D("waf_user_agent")
if waf_url() then return true end
-- C:D("waf_url")
-- cc setting
if waf_cc_increase() then return true end
-- C:D("waf_cc_increase")
if waf_cc() then return true end
-- C:D("waf_cc")
-- cookie检查
if waf_cookie() then return true end
-- C:D("waf_cookie")
-- args参数拦截
if waf_get_args() then return true end
-- C:D("waf_get_args")
-- 扫描软件禁止
if waf_scan_black() then return true end
-- C:D("waf_scan_black")
if waf_post() then return true end
-- C:D("waf_post")
--------------------------------------------------------
--------------------------------------------------------
if X_Forwarded() then return true end
-- C:D("X_Forwarded")
if post_X_Forwarded() then return true end
-- C:D("post_X_Forwarded")
if url_ext() then return true end
-- C:D("url_ext")
if post_data() then return true end
-- C:D("post_data")
end
end

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