Compare commits

...
835 Commits
Author SHA1 Message Date
Mr Chen 6451d1caa1 u 2019-02-26 15:47:51 +08:00
Mr Chen ca8d2ac405 Update public.py 2019-02-26 15:30:21 +08:00
Mr Chen 9f9922abdd Update system_api.py 2019-02-26 15:30:19 +08:00
Mr Chen 9ec0987cfa Update index.js 2019-02-26 15:30:12 +08:00
Mr Chen c21ad861af Update index.html 2019-02-26 15:30:08 +08:00
Mr Chen eac65528c7 Update layout.html 2019-02-26 15:30:05 +08:00
Mr Chen 291071a3a3 插件安装 2019-02-26 11:26:29 +08:00
Mr Chen c454f7ddbe u 2019-02-26 11:26:17 +08:00
Mr Chen 9e6a95460b Update site_api.py 2019-02-26 10:13:31 +08:00
midoks 5a4b06f12e u 2019-02-25 22:29:24 +08:00
Mr Chen 9def3d0854 Update plugin_compress.sh 2019-02-25 19:37:51 +08:00
Mr Chen 2183c74aa2 加入压缩脚本 2019-02-25 18:07:31 +08:00
Mr Chen 3ffe6102e8 Update index.py 2019-02-25 17:15:53 +08:00
Mr Chen cb21fc08e4 u 2019-02-25 17:10:32 +08:00
Mr Chen ccd819d18a u 2019-02-25 15:41:01 +08:00
Mr Chen 532f458993 站点启停 2019-02-25 15:18:26 +08:00
Mr Chen abc74b3e3b Update index.py 2019-02-25 15:18:08 +08:00
Mr Chen 1d6664f01a u 2019-02-25 14:22:49 +08:00
Mr Chen c5f11d6819 网站备份 2019-02-25 14:07:56 +08:00
Mr Chen 495a46deec u 2019-02-25 11:52:55 +08:00
midoks 7863a7b50d u 2019-02-24 23:54:06 +08:00
midoks cb4a4d0568 u 2019-02-24 23:17:28 +08:00
midoks 639ee1c0ba update 2019-02-24 19:40:36 +08:00
midoks 1a380c2745 子目录绑定功能 2019-02-24 18:04:51 +08:00
midoks 4b4164f146 i 2019-02-23 14:42:47 +08:00
midoks 728add52d1 u 2019-02-23 11:25:39 +08:00
midoks 2b694bee35 Update system_api.py 2019-02-22 21:18:25 +08:00
midoks 9f4e4b8541 Update default.sql 2019-02-22 20:59:05 +08:00
midoks 736ceeb730 Update config_api.py 2019-02-22 20:56:34 +08:00
Mr Chen b95804587c 面板收藏功能完成2 2019-02-22 18:04:42 +08:00
Mr Chen 77af5fcf7f 面板收藏功能完成 2019-02-22 18:00:39 +08:00
Mr Chen 2c2aed7d18 Delete ssl.pl 2019-02-22 14:28:06 +08:00
Mr Chen ff543284cc 面板设置功能ok
1.关闭面板
2.ipv6监听
3.面板ssl
2019-02-22 14:22:13 +08:00
Mr Chen 835fea0ad6 uu 2019-02-22 11:47:56 +08:00
midoks 8bbdcdb095 update 2019-02-21 23:05:09 +08:00
midoks 1e8c6ea498 Update .gitignore 2019-02-21 22:22:29 +08:00
Mr Chen da17e7782e update 2019-02-21 19:19:55 +08:00
Mr Chen 11c9a9d736 u 2019-02-21 19:13:39 +08:00
Mr Chen b77c5ce39a Update simdht_worker.py 2019-02-21 17:39:40 +08:00
Mr Chen 795322d77a simdht优化 2019-02-21 17:30:01 +08:00
Mr Chen 78168a1df0 Update firewall.html 2019-02-21 15:43:24 +08:00
Mr Chen 12b99b7c87 u 2019-02-21 15:40:27 +08:00
Mr Chen 7976c16965 r 2019-02-21 15:31:36 +08:00
Mr Chen 31de75f3ff u 2019-02-21 15:29:42 +08:00
Mr Chen 45d14c4ad4 Update config_api.py 2019-02-21 15:27:54 +08:00
Mr Chen fc6ce6c614 update 2019-02-21 15:26:14 +08:00
Mr Chen b2b0716a48 Update firewall_api.py 2019-02-21 15:15:47 +08:00
Mr Chen 0ce33bb170 update 2019-02-21 15:04:58 +08:00
Mr Chen e8fb2a231a Update firewall.js 2019-02-21 15:01:23 +08:00
Mr Chen 9bafcaef7c Update firewall.html 2019-02-21 15:00:19 +08:00
Mr Chen 6cf91549be u 2019-02-21 14:57:57 +08:00
Mr Chen 80c9cafae1 u 2019-02-21 14:35:37 +08:00
Mr Chen 6487cbae09 Update firewall_api.py 2019-02-21 14:32:30 +08:00
Mr Chen 2f1b080870 u 2019-02-21 14:28:51 +08:00
Mr Chen cef24d3084 update 2019-02-21 13:53:46 +08:00
Mr Chen ca03199583 Update firewall_api.py 2019-02-21 13:50:04 +08:00
Mr Chen 4170b790bf Update firewall_api.py 2019-02-21 13:46:14 +08:00
Mr Chen 97f9391c41 Update firewall_api.py 2019-02-21 13:44:05 +08:00
Mr Chen 5f704ec742 u 2019-02-21 13:37:51 +08:00
Mr Chen 1ea7632b38 Update firewall.js 2019-02-21 13:34:13 +08:00
Mr Chen 61853ee530 u 2019-02-21 13:24:12 +08:00
Mr Chen 3d82092e1a u 2019-02-21 12:40:18 +08:00
Mr Chen 0ba8620966 Update firewall.js 2019-02-21 11:30:01 +08:00
Mr Chen d657d7a322 Update system_api.py 2019-02-21 11:26:18 +08:00
Mr Chen 95a9bc8d5f 功能OK
面板操作日志已清空!
2019-02-21 11:23:01 +08:00
Mr Chen 1bfc2e9c1c 内存使用率功能优化 2019-02-21 10:49:36 +08:00
Mr Chen a81b16a27a Update backup.py 2019-02-20 18:31:08 +08:00
Mr Chen 3d67694786 u 2019-02-20 18:18:21 +08:00
Mr Chen 22b65e3bba Update crontab_api.py 2019-02-20 18:02:51 +08:00
Mr Chen 3874cbee86 Delete libList.conf 2019-02-20 18:02:09 +08:00
Mr Chen 990f52dd81 update 2019-02-20 18:01:51 +08:00
Mr Chen 9f0be85a9f 文件上传OK 2019-02-20 13:27:13 +08:00
Mr Chen 4ae442ae4c update 2019-02-19 18:59:27 +08:00
Mr Chen d0514fdca1 update 2019-02-19 17:29:07 +08:00
Mr Chen 093ceae9d4 Update files.js 2019-02-19 14:59:18 +08:00
Mr Chen cfb6fb07ac update 2019-02-19 14:51:27 +08:00
Mr Chen ea3ece1639 update 2019-02-19 14:28:16 +08:00
Mr Chen ef4d35cee7 Update setting.py 2019-02-19 14:13:33 +08:00
Mr Chen d6e79d057a Update setting.py 2019-02-19 14:10:06 +08:00
Mr Chen 17022f2fcb Update __init__.py 2019-02-19 14:05:03 +08:00
Mr Chen b4a371f1a1 Update setting.py 2019-02-19 14:04:40 +08:00
Mr Chen 831bb240d1 Update __init__.py 2019-02-19 14:03:14 +08:00
Mr Chen b3ea4a8307 Update __init__.py 2019-02-19 14:02:26 +08:00
Mr Chen 5f607ded95 Update webssh.js 2019-02-19 13:57:53 +08:00
Mr Chen cc01156b8c Update webssh.js 2019-02-19 13:55:10 +08:00
Mr Chen b208a5d751 Update webssh.js 2019-02-19 13:54:02 +08:00
Mr Chen 72c31b8aaf Update webssh.js 2019-02-19 13:51:10 +08:00
Mr Chen 5bd6f43b2a Update webssh.js 2019-02-19 13:48:59 +08:00
Mr Chen e8f0cc5003 Update webssh.js 2019-02-19 13:47:56 +08:00
Mr Chen 34d17289cc Update webssh.js 2019-02-19 13:45:20 +08:00
Mr Chen 30bc6f27ec update 2019-02-19 13:31:09 +08:00
Mr Chen 77a36e6cfd Update __init__.py 2019-02-19 13:25:31 +08:00
Mr Chen 2ff70a2c32 Update webssh.js 2019-02-19 13:24:51 +08:00
Mr Chen 782389972b update 2019-02-19 13:21:19 +08:00
Mr Chen 60fd8d306b u 2019-02-19 13:17:26 +08:00
Mr Chen e341272547 Update __init__.py 2019-02-19 13:12:17 +08:00
Mr Chen a28e9e2dbf Update __init__.py 2019-02-19 13:12:01 +08:00
Mr Chen 1041f64c93 gevent模式 2019-02-19 11:37:24 +08:00
midoks 7c6d13473f u 2019-02-19 00:01:30 +08:00
Mr Chen cd38c261b7 update 2019-02-18 20:05:30 +08:00
Mr Chen 091f5f3fbb Update __init__.py 2019-02-18 18:20:57 +08:00
Mr Chen 212798426b update 2019-02-18 16:38:40 +08:00
Mr Chen 29fa997ad2 update 2019-02-18 16:21:31 +08:00
midoks c36cf7d83e update 2019-02-17 23:53:33 +08:00
midoks 8b6bdd25d9 u 2019-02-17 22:10:14 +08:00
midoks f7b3fbc249 uu 2019-02-17 19:09:55 +08:00
midoks baf091d8c3 u 2019-02-17 17:35:50 +08:00
midoks 6831c00c2a i 2019-02-17 16:33:19 +08:00
midoks 4050d9697b u 2019-02-17 15:06:54 +08:00
midoks 9872bf5e61 update 2019-02-17 14:42:51 +08:00
midoks 24f8a551d8 Update files.js 2019-02-16 20:51:47 +08:00
midoks 7dcc584c87 update 2019-02-16 20:40:58 +08:00
midoks 7a94dd9ad9 Update files.js 2019-02-16 19:32:20 +08:00
midoks 643f4f177c y 2019-02-16 18:49:23 +08:00
midoks b2a1530b01 Update qbittorrent_worker.py 2019-02-16 16:12:06 +08:00
midoks 7753e7a7c1 Update qbittorrent_worker.py 2019-02-16 15:52:38 +08:00
midoks 19a9bf6554 Update qbittorrent_worker.py 2019-02-16 12:43:58 +08:00
midoks 477c48080b Update qbittorrent_worker.py 2019-02-16 03:35:24 +08:00
midoks 332324d218 Update qbittorrent_worker.py 2019-02-16 02:34:32 +08:00
midoks f6928c1784 Update qbittorrent_worker.py 2019-02-16 02:29:55 +08:00
midoks dd7b2c30a2 Update qbittorrent_worker.py 2019-02-16 02:13:59 +08:00
midoks 763744b4a5 通用的手动编辑 2019-02-16 01:20:56 +08:00
midoks 8e3202b354 Update commit.tpl 2019-02-16 01:11:41 +08:00
Mr Chen 2a148c9309 gogs base ok 2019-02-15 20:19:41 +08:00
Mr Chen 159c4d57b3 Update yaf.sh 2019-02-15 12:59:06 +08:00
midoks aee172170e u 2019-02-15 00:21:56 +08:00
Mr Chen 845fc8104a update 2019-02-14 17:50:32 +08:00
Mr Chen ef91abab77 update 2019-02-14 16:25:07 +08:00
Mr Chen ea295d1e0a update 2019-02-14 15:19:36 +08:00
Mr Chen ed83c1da60 Update app.ini 2019-02-14 14:31:19 +08:00
Mr Chen 752b400c6c update 2019-02-14 14:28:11 +08:00
Mr Chen 6fb2e94e05 update 2019-02-14 12:02:16 +08:00
midoks 8cf1cfad59 up 2019-02-14 02:11:48 +08:00
Mr Chen 8eb7e20654 Update index.py 2019-02-13 19:58:42 +08:00
Mr Chen a62fe19491 Update index.py 2019-02-13 19:56:38 +08:00
Mr Chen 77ebd5bc36 Update install.sh 2019-02-13 19:52:39 +08:00
Mr Chen 49873a5249 update 2019-02-13 19:49:02 +08:00
Mr Chen 6c90f2a7c3 Update site_api.py 2019-02-13 17:17:49 +08:00
Mr Chen 13061a3808 update 2019-02-13 16:41:29 +08:00
Mr Chen e3aab8c8da update 2019-02-13 16:02:16 +08:00
Mr Chen dab3920618 update 2019-02-13 14:23:11 +08:00
Mr Chen 5ff24872b9 Update public.py 2019-02-13 11:28:47 +08:00
Mr Chen e7e0295446 update 2019-02-13 11:21:38 +08:00
Mr Chen 97752b690e update 2019-02-13 11:20:51 +08:00
midoks 8894280ad7 u 2019-02-12 23:30:28 +08:00
Mr Chen 4a3ac08498 Update site_api.py 2019-02-12 19:44:17 +08:00
Mr Chen 497981b4fc Update site_api.py 2019-02-12 19:41:39 +08:00
Mr Chen ac6d714c01 update 2019-02-12 18:43:28 +08:00
midoks 858540a440 update 2019-02-11 23:25:43 +08:00
Mr Chen a9300b0e43 update 2019-02-11 19:22:53 +08:00
Mr Chen abc04b7995 Update site_api.py 2019-02-11 18:03:27 +08:00
Mr Chen 208d892675 update 2019-02-11 17:57:29 +08:00
Mr Chen 3b83c0538f Update index.py 2019-02-11 16:24:29 +08:00
Mr Chen 35bd7d4cc1 Update sphinx.js 2019-02-11 16:23:51 +08:00
Mr Chen 6effc0ed8f Update sphinx.js 2019-02-11 16:19:21 +08:00
Mr Chen d50011d1e2 update 2019-02-11 16:00:29 +08:00
Mr Chen 3e9cbf89da Update nginx.conf 2019-02-11 14:40:47 +08:00
midoks f7df26a118 Update index.py 2019-02-10 12:43:24 +08:00
midoks f5fe6ad747 update 2019-02-10 12:27:17 +08:00
midoks c45b2d8d5f Update qbittorrent_worker.py 2019-02-10 00:52:00 +08:00
Mr Chen 48729c39df Update simdht_worker.py 2019-02-09 21:43:50 +08:00
Mr Chen 8946d8a12f Update qbittorrent_worker.py 2019-02-09 19:39:23 +08:00
Mr Chen 3783ab407b Update simdht.tpl 2019-02-09 18:17:25 +08:00
Mr Chen 14f59c7ae7 Update simdht_worker.py 2019-02-09 18:15:40 +08:00
Mr Chen a080a4f5f6 update 2019-02-09 14:00:52 +08:00
Mr Chen e43b66618c update 2019-02-09 12:43:46 +08:00
Mr Chen f2362bd7a2 Update qbittorrent_worker.py 2019-02-08 01:01:25 +08:00
Mr Chen e7513c7ed7 Update qb.sql 2019-02-08 01:00:15 +08:00
Mr Chen 0cdc743b4f Update qbittorrent_worker.py 2019-02-07 19:25:55 +08:00
Mr Chen 16e964ccbe Update qbittorrent_worker.py 2019-02-07 19:23:50 +08:00
Mr Chen d3d6feae0a Update index.py 2019-02-07 18:58:36 +08:00
Mr Chen 31fa78c31c Update qbittorrent_worker.py 2019-02-07 17:25:55 +08:00
Mr Chen 9cce88755e Update qbittorrent_worker.py 2019-02-07 15:36:23 +08:00
Mr Chen 973e2fa1ac Update qb.sql 2019-02-05 19:37:33 +08:00
Mr Chen 5645431d90 Update site.css 2019-02-05 15:42:02 +08:00
Mr Chen 4c660e307a Update crontab.js 2019-02-03 20:29:40 +08:00
Mr Chen c76ed0ae97 update 2019-02-03 02:05:17 +08:00
Mr Chen 8144de6ced Update install_centos.sh 2019-02-02 23:02:28 +08:00
Mr Chen 328c84e78a Update install.sh 2019-02-02 22:58:54 +08:00
Mr Chen 679a10104f Update install_centos.sh 2019-02-02 22:19:37 +08:00
Mr Chen c9e307382d Update install_centos.sh 2019-02-02 22:14:57 +08:00
Mr Chen bc4d25871d Update install.sh 2019-02-02 22:13:51 +08:00
Mr Chen d11a10e607 Update install_centos.sh 2019-02-02 19:38:16 +08:00
Mr Chen 01cfa5a8d0 u 2019-02-02 18:53:07 +08:00
Mr Chen c880e935d7 Update install_centos.sh 2019-02-02 18:04:42 +08:00
Mr Chen 4b67f348f6 Update install_centos.sh 2019-02-02 18:02:59 +08:00
Mr Chen 2a9bfe15c0 Update install_centos.sh 2019-02-02 18:01:34 +08:00
Mr Chen bb8a6a3a2c Update install_centos.sh 2019-02-02 18:00:09 +08:00
Mr Chen d6b5a019cf update 2019-02-02 17:58:32 +08:00
Mr Chen d623cab022 Update install_centos.sh 2019-02-02 17:53:19 +08:00
Mr Chen 26748bbeaa up 2019-02-02 16:22:37 +08:00
Mr Chen e211cc075f update 2019-01-30 14:14:14 +08:00
Mr Chen f52d8c0fbb Update qb.sql 2019-01-29 00:49:46 +08:00
Mr Chen 22f6f04c8a Update qb.sql 2019-01-29 00:39:06 +08:00
Mr Chen bd4972e55d update 2019-01-29 00:23:34 +08:00
Mr Chen 3318218764 update 2019-01-28 21:16:32 +08:00
Mr Chen fe468421f2 Update firewall.js 2019-01-27 16:32:37 +08:00
Mr Chen fee05f6af3 Update firewall.js 2019-01-27 16:17:24 +08:00
Mr Chen 04c09ed101 Update firewall.js 2019-01-27 16:15:43 +08:00
Mr Chen 142437ea7e Update firewall_api.py 2019-01-26 23:34:36 +08:00
Mr Chen bf3ddbf4a5 Update firewall_api.py 2019-01-26 23:24:25 +08:00
Mr Chen 602ef37d88 Update firewall.js 2019-01-26 23:15:36 +08:00
Mr Chen 9c860a5941 u 2019-01-26 22:47:00 +08:00
Mr Chen 242ffd4517 Update qbittorrent_worker.py 2019-01-26 20:05:06 +08:00
Mr Chen 6821f7a895 Update qbittorrent_worker.py 2019-01-26 19:47:31 +08:00
Mr Chen 2bb03a71c6 Update qbittorrent_worker.py 2019-01-26 19:46:24 +08:00
Mr Chen 433cf508e5 Update qbittorrent_worker.py 2019-01-26 19:34:43 +08:00
Mr Chen bdb852c8cf Update qbittorrent_worker.py 2019-01-26 19:31:31 +08:00
Mr Chen cf008c7ccd Update qbittorrent_worker.py 2019-01-26 19:25:29 +08:00
Mr Chen 1f1870c5e2 Update qbittorrent_worker.py 2019-01-26 18:19:35 +08:00
Mr Chen aecabf7dd2 update 2019-01-26 18:05:01 +08:00
Mr Chen 342652abe8 Update crontab_api.py 2019-01-26 18:00:49 +08:00
Mr Chen 0bbe4f6ffc Update qbittorrent_worker.py 2019-01-26 17:37:55 +08:00
Mr Chen 4411b4e70f Update qbittorrent_worker.py 2019-01-26 17:30:43 +08:00
Mr Chen b4757dfadd Update qbittorrent_worker.py 2019-01-26 13:47:17 +08:00
Mr Chen ed465ad8cf update 2019-01-26 13:10:07 +08:00
Mr Chen 2896e2d9fb update 2019-01-25 19:08:22 +08:00
Mr Chen f6ff5c8e26 update 2019-01-25 18:10:33 +08:00
Mr Chen d6dfccb5bc update 2019-01-25 13:41:53 +08:00
Mr Chen d6007b273c Update qbittorrent_worker.py 2019-01-25 10:42:41 +08:00
Mr Chen b7da5f7db3 Update qbittorrent_worker.py 2019-01-25 10:36:40 +08:00
Mr Chen 58258afe6e Update qbittorrent_worker.py 2019-01-25 10:34:56 +08:00
midoks 139b1cf03b Update qbittorrent_worker.py 2019-01-25 02:39:25 +08:00
midoks 8e3e170c6e Update qbittorrent_worker.py 2019-01-25 02:17:51 +08:00
midoks 51c50c8fc6 Update qbittorrent_worker.py 2019-01-25 01:56:06 +08:00
midoks 3513230de1 Update qbittorrent_worker.py 2019-01-24 23:33:33 +08:00
midoks 4b72cd448d Update qbittorrent_worker.py 2019-01-24 23:14:04 +08:00
midoks 7096a65591 Update qbittorrent_worker.py 2019-01-24 23:03:44 +08:00
Mr Chen 7b36b808bd Update qbittorrent_worker.py 2019-01-24 17:57:59 +08:00
Mr Chen 3a4467619e Update qbittorrent_worker.py 2019-01-24 17:57:05 +08:00
Mr Chen f928ef95f6 Update qbittorrent_worker.py 2019-01-24 17:46:55 +08:00
Mr Chen 9cf984ed65 Update qbittorrent_worker.py 2019-01-24 17:45:22 +08:00
Mr Chen 1f14e271c4 Update index.py 2019-01-24 17:43:14 +08:00
Mr Chen dddf0edb26 Update qbittorrent_worker.py 2019-01-24 17:42:14 +08:00
Mr Chen 8ac906f11e Update qbittorrent_worker.py 2019-01-24 17:39:59 +08:00
Mr Chen 243c1d2291 Update qbittorrent_worker.py 2019-01-24 17:37:18 +08:00
Mr Chen 072bd93ac0 Update qbittorrent_worker.py 2019-01-24 17:25:33 +08:00
Mr Chen a3d2183eef Update qbittorrent_worker.py 2019-01-24 17:15:48 +08:00
Mr Chen 71ffa35702 Update qb.conf 2019-01-24 17:14:15 +08:00
Mr Chen c28e48557d Update qbittorrent_worker.py 2019-01-24 17:13:58 +08:00
Mr Chen c6c88c0841 Update qb.conf 2019-01-24 17:11:35 +08:00
Mr Chen 9dbc4baa25 update 2019-01-24 17:11:09 +08:00
Mr Chen 0f7a493777 Update qbittorrent_worker.py 2019-01-24 17:04:53 +08:00
Mr Chen cd4c21697d Update qbittorrent_worker.py 2019-01-24 16:58:46 +08:00
Mr Chen e45832ea22 Update qbittorrent_worker.py 2019-01-24 16:56:58 +08:00
Mr Chen 603323f576 Update qbittorrent.tpl 2019-01-24 16:55:04 +08:00
Mr Chen 421e1d5623 Update qbittorrent.tpl 2019-01-24 16:52:36 +08:00
Mr Chen 2492d38a1d Update index.py 2019-01-24 16:51:48 +08:00
Mr Chen 22a023b877 Update qbittorrent_worker.py 2019-01-24 16:48:39 +08:00
Mr Chen b1f95fb5f2 Update qbittorrent_worker.py 2019-01-24 16:48:08 +08:00
Mr Chen 7641d03f34 Update qbittorrent_worker.py 2019-01-24 16:37:26 +08:00
Mr Chen d2b9fbed4a update 2019-01-24 16:28:52 +08:00
Mr Chen 67abcc17c5 update 2019-01-24 16:02:59 +08:00
Mr Chen dfdeef8f4c update 2019-01-24 13:46:43 +08:00
Mr Chen 92e23cb018 Update qb.conf 2019-01-24 13:21:37 +08:00
Mr Chen 8e9aa1489e Update qbittorrent_worker.py 2019-01-24 11:37:33 +08:00
Mr Chen 47fc9576dc Update qbittorrent_worker.py 2019-01-24 11:37:22 +08:00
Mr Chen ab1ad909ad update 2019-01-24 11:11:34 +08:00
Mr Chen 1da2a454ad Update index.html 2019-01-24 10:43:33 +08:00
Mr Chen 33a418017a Update qbittorrent.tpl 2019-01-24 10:16:10 +08:00
Mr Chen c0161572f7 Update qbittorrent_worker.py 2019-01-24 10:06:00 +08:00
Mr Chen ba2a061eb1 Update qbittorrent_worker.py 2019-01-24 09:59:58 +08:00
midoks 7535598be6 Update index.py 2019-01-24 00:00:22 +08:00
midoks f98e69ede7 Update qbittorrent_worker.py 2019-01-23 23:51:17 +08:00
midoks 9d88675756 Update qbittorrent_worker.py 2019-01-23 23:48:21 +08:00
midoks 8c07db3b57 Update qbittorrent_worker.py 2019-01-23 23:44:20 +08:00
Mr Chen a226c3c019 Update qbittorrent_worker.py 2019-01-23 20:59:50 +08:00
Mr Chen 8533d667cd Update qbittorrent_worker.py 2019-01-23 20:52:34 +08:00
Mr Chen 4b1f483565 Update qbittorrent.tpl 2019-01-23 20:51:56 +08:00
Mr Chen ede5bab112 update 2019-01-23 20:50:04 +08:00
Mr Chen be5fc96998 Update install.sh 2019-01-23 20:36:03 +08:00
Mr Chen ffbe43b589 Update install.sh 2019-01-23 20:35:45 +08:00
Mr Chen e2ae038fa2 Update qbittorrent_worker.py 2019-01-23 20:28:59 +08:00
Mr Chen f9482c43c7 Update qbittorrent_worker.py 2019-01-23 20:24:54 +08:00
Mr Chen b4898e32a5 Update qbittorrent_worker.py 2019-01-23 20:23:30 +08:00
Mr Chen 0094d4e573 Update qbittorrent_worker.py 2019-01-23 19:55:21 +08:00
Mr Chen ffd1258d26 Update qbittorrent_worker.py 2019-01-23 19:50:46 +08:00
Mr Chen f46139e1f9 Update qbittorrent.tpl 2019-01-23 19:48:02 +08:00
Mr Chen 4eb68cbdbb Update qbittorrent_worker.py 2019-01-23 19:47:13 +08:00
Mr Chen 5b164ee478 update 2019-01-23 19:44:37 +08:00
Mr Chen 619bbca29d Update qb.conf 2019-01-23 19:38:50 +08:00
Mr Chen 32dfc0a1ab Update qbittorrent_worker.py 2019-01-23 19:35:35 +08:00
Mr Chen 7124f314ac Update qbittorrent_worker.py 2019-01-23 15:14:06 +08:00
Mr Chen 526ba2cd65 Update qbittorrent_worker.py 2019-01-23 13:44:12 +08:00
Mr Chen 9fce92c7d5 Update qb.conf 2019-01-23 13:43:09 +08:00
Mr Chen 7102f809c2 update 2019-01-23 13:41:28 +08:00
Mr Chen cb8d396b98 update 2019-01-23 09:57:24 +08:00
midoks 7c22685f49 Update qb.conf 2019-01-22 23:19:17 +08:00
midoks 0ae83fe2b2 Update index.py 2019-01-22 23:17:39 +08:00
midoks 6ec4c72219 Update install.sh 2019-01-22 22:56:31 +08:00
Mr Chen d6321dbbb7 update 2019-01-22 19:57:27 +08:00
Mr Chen 3706c64b8f update 2019-01-22 19:28:26 +08:00
Mr Chen 28e5787dc9 update 2019-01-22 18:26:05 +08:00
Mr Chen a8afc4fe88 Update simdht.js 2019-01-22 16:58:23 +08:00
Mr Chen 86326de64f Update simdht_delta.conf 2019-01-22 16:51:20 +08:00
Mr Chen 96d441fe5f update 2019-01-22 16:50:03 +08:00
Mr Chen b610e8f997 Update simdht_delta.conf 2019-01-22 15:56:52 +08:00
Mr Chen 824d58e07f update 2019-01-22 15:00:30 +08:00
Mr Chen 7d0a5713ba update 2019-01-22 14:40:04 +08:00
Mr Chen e59cd0d15d update 2019-01-22 11:04:35 +08:00
midoks 5975d712f8 Update index.py 2019-01-21 23:16:16 +08:00
Mr Chen 42b25fb503 update 2019-01-21 18:57:37 +08:00
Mr Chen a50cf91428 Update install.sh 2019-01-21 17:37:27 +08:00
Mr Chen db55a16503 Update install.sh 2019-01-21 16:26:33 +08:00
Mr Chen 100ac12bba Update install.sh 2019-01-21 16:24:38 +08:00
Mr Chen 682c155ada Update install.sh 2019-01-21 16:04:45 +08:00
Mr Chen 3cbb91409d Update install.sh 2019-01-21 15:57:07 +08:00
Mr Chen a1508357ee Update install.sh 2019-01-21 15:13:35 +08:00
Mr Chen d4742f061b Update install.sh 2019-01-21 15:07:17 +08:00
Mr Chen 669259634a update 2019-01-21 15:05:56 +08:00
Mr Chen 0050d85b8e Update simdht.sql 2019-01-21 14:46:35 +08:00
Mr Chen 17b810436e Update install.sh 2019-01-21 14:12:39 +08:00
Mr Chen 7249ec56c0 Update install.sh 2019-01-21 14:11:10 +08:00
Mr Chen 537346dace qbittorrent 2019-01-21 14:10:25 +08:00
Mr Chen d83a4fe27f update 2019-01-21 11:27:21 +08:00
Mr Chen 56168b76fb Update my.cnf 2019-01-21 10:27:25 +08:00
midoks 6bcf3c5d35 Update index.py 2019-01-20 23:07:50 +08:00
Mr Chen edf44d09e1 Update public.py 2019-01-19 17:47:27 +08:00
Mr Chen 31e48ffc53 Update index.py 2019-01-19 16:49:50 +08:00
Mr Chen 030aa7b46c Update index.py 2019-01-19 16:45:14 +08:00
Mr Chen ea6be0b69a Update public.js 2019-01-19 16:43:20 +08:00
Mr Chen e172aa3a6e Update public.py 2019-01-19 16:41:11 +08:00
Mr Chen 6d8048af2f Update public.py 2019-01-19 16:39:57 +08:00
Mr Chen ec3f8c0249 update 2019-01-19 16:37:08 +08:00
Mr Chen ddd8a32abf Update index.py 2019-01-19 16:35:39 +08:00
Mr Chen 3b842620a0 Update index.py 2019-01-19 16:33:35 +08:00
Mr Chen 553b2b10d9 Update public.py 2019-01-19 16:26:52 +08:00
Mr Chen 177369585c Update public.py 2019-01-19 16:25:45 +08:00
Mr Chen 1977fa025a Update index.py 2019-01-19 16:24:31 +08:00
Mr Chen 13fd61f0cf Update index.py 2019-01-19 16:20:20 +08:00
Mr Chen 7ef6cdd76c Update index.py 2019-01-19 15:59:27 +08:00
Mr Chen b1b1878637 Update index.py 2019-01-19 15:57:43 +08:00
Mr Chen 17f8b47625 Update public.py 2019-01-19 15:51:26 +08:00
Mr Chen d7e7f5ea2d Update simdht.js 2019-01-19 15:33:17 +08:00
Mr Chen 6efa3e6a35 up 2019-01-19 15:31:17 +08:00
Mr Chen e3e1545c9b Update common.py 2019-01-19 15:20:51 +08:00
Mr Chen b26737eb3c Update common.py 2019-01-19 15:12:44 +08:00
midoks 4eb430a88b update 2019-01-19 03:05:55 +08:00
Mr Chen bfa0add999 update 2019-01-18 17:22:06 +08:00
Mr Chen 7f20090e8c update 2019-01-18 17:11:29 +08:00
Mr Chen e151f0dee1 Update info.json 2019-01-18 16:20:25 +08:00
Mr Chen a5184e933e update 2019-01-18 16:05:21 +08:00
Mr Chen 819e74333e 优化 2019-01-18 15:46:59 +08:00
Mr Chen 4a09c3fd95 Update install.sh 2019-01-18 13:17:20 +08:00
Mr Chen c214c19a89 Update install.sh 2019-01-18 12:59:20 +08:00
Mr Chen 889de6769a Update soft.js 2019-01-18 11:30:53 +08:00
Mr Chen 7dfe6eb681 Update install.sh 2019-01-18 11:29:32 +08:00
Mr Chen ef21d5f47f Update install.sh 2019-01-18 11:22:23 +08:00
midoks 2d8e62417f update 2019-01-17 23:30:25 +08:00
midoks d2750f41aa update 2019-01-17 23:16:45 +08:00
Mr Chen 0ab7af4748 Update index.html 2019-01-17 16:04:38 +08:00
Mr Chen 56cc3b75c3 update 2019-01-17 15:31:57 +08:00
Mr Chen 127caf661c u 2019-01-17 14:19:48 +08:00
Mr Chen 9bc857b000 update 2019-01-17 14:19:06 +08:00
Mr Chen 233fa4cf60 Update index.html 2019-01-17 11:35:33 +08:00
Mr Chen d5b8f7f800 Update index.html 2019-01-17 11:33:27 +08:00
Mr Chen b595557f2c Update install.sh 2019-01-17 10:23:37 +08:00
midoks d90509e479 Update plugins_api.py 2019-01-16 22:50:17 +08:00
Mr Chen e1e84741f5 update 2019-01-16 15:35:22 +08:00
Mr Chen 9169ce58de update 2019-01-16 14:56:26 +08:00
Mr Chen 0b55595ce6 update 2019-01-16 13:54:03 +08:00
Mr Chen b5aeaacc69 Update sphinx.tpl 2019-01-16 13:43:01 +08:00
Mr Chen 1ed469b5f6 update 2019-01-16 13:27:51 +08:00
Mr Chen d900298a7b update 2019-01-16 13:02:05 +08:00
midoks 5ac1642927 sphinx init 2019-01-15 23:13:21 +08:00
Mr Chen d1f26a59ce Update install_macos.sh 2019-01-15 20:27:47 +08:00
Mr Chen 7be7de2bce Update install_macos.sh 2019-01-15 20:23:10 +08:00
Mr Chen 91c9250f74 Update install_centos.sh 2019-01-15 18:20:36 +08:00
Mr Chen 91bd3abb74 Update install.sh 2019-01-15 18:19:32 +08:00
Mr Chen 04d6166deb Update install_macos.sh 2019-01-15 18:15:28 +08:00
Mr Chen c66fd7abe0 update 2019-01-15 17:57:33 +08:00
Mr Chen ac71de01bd 两边一致 2019-01-15 16:21:22 +08:00
Mr Chen d0430e7b3c Update pick_filter.txt 2019-01-15 15:41:08 +08:00
Mr Chen 0264e2edda Revert "update"
This reverts commit 631776c0ce.
2019-01-15 15:39:15 +08:00
Mr Chen 631776c0ce update 2019-01-15 15:38:00 +08:00
Mr Chen 008ff29e13 Update mw.tpl 2019-01-15 15:34:40 +08:00
Mr Chen c66105ae96 Create tools.py 2019-01-15 15:06:17 +08:00
Mr Chen 6c2fe6c9de Update memcache.sh 2019-01-15 14:37:02 +08:00
Mr Chen 970cc56ea1 update 2019-01-15 14:31:14 +08:00
Mr Chen 4a582d75df php56 memcache 2019-01-15 14:31:08 +08:00
Mr Chen 9438388877 php56
zendguardloader.sh
2019-01-15 14:01:57 +08:00
Mr Chen cc39d7cb25 mysql 工具功能ok 2019-01-15 12:59:56 +08:00
midoks b7394e2f79 update 2019-01-14 23:29:07 +08:00
Mr Chen ab52563f3f update 2019-01-14 18:03:45 +08:00
Mr Chen c5c49f2ec0 Update php.js 2019-01-14 16:50:57 +08:00
Mr Chen a76c6af147 Update yaf.sh 2019-01-14 16:49:50 +08:00
Mr Chen e71b00669e ipdate 2019-01-14 15:28:27 +08:00
Mr Chen 02df20fc57 update 2019-01-14 13:13:24 +08:00
midoks cc0e4d1064 update 2019-01-13 23:51:09 +08:00
midoks bff6b17839 Update simdht.js 2019-01-13 00:49:04 +08:00
midoks 9c397fff8a update 2019-01-13 00:45:45 +08:00
midoks 255f4b95a0 update 2019-01-12 23:49:41 +08:00
midoks a9ed883407 update 2019-01-12 21:29:07 +08:00
Mr Chen 2b446087fc update 2019-01-11 19:00:16 +08:00
Mr Chen 6e9dc8e9e6 update 2019-01-11 18:12:08 +08:00
Mr Chen a08e48c139 Update index.py 2019-01-11 15:38:30 +08:00
Mr Chen 557aabfaf8 Update simdht_worker.py 2019-01-11 14:56:03 +08:00
Mr Chen 97c02f00a0 Update simdht_worker.py 2019-01-11 14:54:08 +08:00
Mr Chen 2280d41ddd Update simdht_worker.py 2019-01-11 14:39:36 +08:00
Mr Chen 72fb2d1ecc Update simdht_worker.py 2019-01-11 14:38:15 +08:00
Mr Chen 85c88dcde0 Update simdht_worker.py 2019-01-11 14:37:22 +08:00
Mr Chen bd9f7510d3 update 2019-01-11 14:25:26 +08:00
Mr Chen e39b06cf83 Update simdht_worker.py 2019-01-11 14:18:33 +08:00
Mr Chen ed992ff1a3 update 2019-01-11 13:53:25 +08:00
Mr Chen f470ae037f update 2019-01-11 10:40:30 +08:00
Mr Chen b9f9b7c49d Update index.py 2019-01-11 10:38:10 +08:00
Mr Chen 29b525cbee update 2019-01-11 10:35:07 +08:00
midoks 5fd8873068 Update index.html 2019-01-11 02:21:23 +08:00
midoks 7627ba6f4b Update metadata.py 2019-01-11 02:17:54 +08:00
midoks e0b5956ad5 update 2019-01-11 02:13:40 +08:00
midoks d7b09afd02 Update public.js 2019-01-11 01:48:50 +08:00
midoks a5e146e918 update 2019-01-11 01:45:04 +08:00
midoks 666738eb56 Update simdht.js 2019-01-11 01:26:30 +08:00
midoks 75c3701e21 Update simdht_worker.py 2019-01-11 01:13:02 +08:00
midoks 733de4a0ff update 2019-01-11 01:09:23 +08:00
midoks aedb8bba05 update 2019-01-11 00:56:02 +08:00
midoks 003e11eda3 Update simdht.sql 2019-01-11 00:45:52 +08:00
midoks f44de8ec5c Update layout.html 2019-01-11 00:26:33 +08:00
midoks dea8263e98 Update index.py 2019-01-11 00:23:24 +08:00
midoks 40456846a8 update 2019-01-11 00:09:06 +08:00
Mr Chen 99ac5f34f0 update 2019-01-10 21:08:07 +08:00
Mr Chen bef1c16cb5 Update simdht_worker.py 2019-01-10 18:05:11 +08:00
Mr Chen d1282b667d Update db.cfg 2019-01-10 18:03:33 +08:00
Mr Chen 222b878c79 Update simdht_worker.py 2019-01-10 17:55:29 +08:00
Mr Chen 9bd6ec598d update 2019-01-10 17:50:53 +08:00
Mr Chen 8bff295837 Update index.py 2019-01-10 14:52:22 +08:00
Mr Chen f28b0c3878 Update public.js 2019-01-10 14:48:44 +08:00
Mr Chen 58fa31352e update 2019-01-10 13:13:18 +08:00
midoks afa2e2e773 update 2019-01-10 01:07:53 +08:00
midoks 0b7548d10f update 2019-01-10 00:52:03 +08:00
Mr Chen f53b4f4139 Update mysql.js 2019-01-09 19:52:05 +08:00
Mr Chen f338814f97 Update mysql.js 2019-01-09 19:38:00 +08:00
Mr Chen 28f2b28a53 update 2019-01-09 19:28:21 +08:00
Mr Chen e0861a2a9e up 2019-01-09 16:37:57 +08:00
Mr Chen 72e23f11a4 Update index.py 2019-01-09 16:10:31 +08:00
Mr Chen 256be27d3a update 2019-01-09 16:10:01 +08:00
Mr Chen 482759a0e9 update 2019-01-09 13:51:14 +08:00
midoks 0faf8036da Update mysql.js 2019-01-08 23:38:36 +08:00
Mr Chen c8289a732c update 2019-01-08 20:23:18 +08:00
Mr Chen a579e5b1d6 update 2019-01-08 17:44:30 +08:00
Mr Chen 5aa714876f update 2019-01-08 17:23:05 +08:00
Mr Chen b75c1c1049 update 2019-01-08 14:51:45 +08:00
Mr Chen 9c03f9d8b7 update 2019-01-08 11:35:36 +08:00
midoks f255eb1fda up 2019-01-07 23:31:13 +08:00
Mr Chen f7d17302a5 Update index.html 2019-01-07 19:58:38 +08:00
Mr Chen 161d9656a8 update 2019-01-07 19:56:53 +08:00
Mr Chen d76f0b22f8 update 2019-01-07 18:05:45 +08:00
Mr Chen 96f3e36183 Update index.py 2019-01-07 14:05:24 +08:00
Mr Chen f13b4c73b2 Update gogs.tpl 2019-01-07 14:03:11 +08:00
Mr Chen aa0f53f2fb update 2019-01-07 13:49:03 +08:00
Mr Chen fcd3088bee Update index.py 2019-01-07 13:48:54 +08:00
midoks 889757d42e up 2019-01-06 23:00:32 +08:00
midoks 4204310442 Update index.py 2019-01-06 21:50:01 +08:00
midoks 3209837e99 phpmyadmin init 2019-01-06 21:20:17 +08:00
midoks 7ad3aa3b21 update 2019-01-06 20:03:27 +08:00
midoks e9ddd3bfa2 Update index.py 2019-01-06 17:14:55 +08:00
midoks 7a0042ff65 Update my.cnf 2019-01-06 16:33:09 +08:00
midoks e5662b4ae7 Update install.sh 2019-01-06 16:21:48 +08:00
midoks 1ac3b3ae9d Update index.py 2019-01-06 16:19:06 +08:00
midoks 29e81cfdfe Update index.py 2019-01-06 16:12:02 +08:00
midoks a1cf9fc980 up 2019-01-06 16:04:06 +08:00
midoks 2072955c37 Update mysql.js 2019-01-06 16:01:30 +08:00
midoks 8cc15d0c00 Update index.py 2019-01-06 15:25:37 +08:00
midoks aaca84e1bc update 2019-01-06 15:17:20 +08:00
midoks 906cf1a8dc 数据库调整 2019-01-06 13:12:53 +08:00
midoks b4c22268b1 Update index.py 2019-01-06 11:33:41 +08:00
midoks 157280c508 update 2019-01-05 22:06:15 +08:00
midoks 266ec5fde3 Update index.py 2019-01-05 19:46:18 +08:00
midoks 17a873b775 update 2019-01-05 19:10:58 +08:00
midoks 27294b5c35 Update index.py 2019-01-05 15:14:57 +08:00
midoks 28fcdd303f u 2019-01-05 15:07:40 +08:00
midoks 329adc2f6f update 2019-01-05 14:26:19 +08:00
midoks 5e076aee60 Update index.py 2019-01-05 11:42:29 +08:00
midoks c95ea69f16 Update index.py 2019-01-05 11:41:08 +08:00
Mr Chen 5a52354541 update 2019-01-04 19:16:47 +08:00
Mr Chen 4ebf6af532 Update index.py 2019-01-04 18:07:50 +08:00
Mr Chen 5a8e903695 Update pure-ftpd.conf 2019-01-04 18:02:03 +08:00
Mr Chen 667956a6b9 update 2019-01-04 17:56:41 +08:00
Mr Chen 3834eda363 Update index.py 2019-01-04 16:32:19 +08:00
Mr Chen 58bd54ee67 Update index.py 2019-01-04 16:23:39 +08:00
Mr Chen e7c228cd35 Update db.py 2019-01-04 16:11:33 +08:00
Mr Chen 8d948ca74b ftp基本ok 2019-01-04 15:31:19 +08:00
Mr Chen 16c9103549 update 2019-01-04 14:20:30 +08:00
Mr Chen a461c143ee u 2019-01-04 11:53:31 +08:00
Mr Chen a3ca576667 Update ftp.js 2019-01-03 19:08:34 +08:00
Mr Chen f2bdce2ec1 搜索 2019-01-03 18:49:38 +08:00
Mr Chen ba560eb468 update 2019-01-03 17:34:23 +08:00
Mr Chen dc2c87999a update 2019-01-03 11:03:46 +08:00
midoks 174cf75755 up 2019-01-03 00:39:19 +08:00
Mr Chen 0f4a16ace6 update 2019-01-02 18:27:00 +08:00
Mr Chen 32a2acf61b update 2019-01-02 17:48:55 +08:00
Mr Chen 328b67bd88 u 2019-01-02 17:02:24 +08:00
Mr Chen 0d6f9b5c5f update 2019-01-02 16:54:52 +08:00
Mr Chen b359a594cd Update soft.js 2019-01-02 16:43:07 +08:00
Mr Chen 8e31452c19 update 2019-01-02 16:27:18 +08:00
Mr Chen 54ded3ae58 updata 2019-01-02 16:13:21 +08:00
Mr Chen 7a8ab1acf1 update 2019-01-02 13:58:53 +08:00
Mr Chen e4179b4ae5 update 2019-01-02 13:29:29 +08:00
Mr Chen 80fb58cefe Update index.html 2018-12-29 16:29:14 +08:00
Mr Chen 87c8b585f8 Delete announce_server.py 2018-12-29 13:09:51 +08:00
Mr Chen 90bc1750c7 update 2018-12-29 12:42:29 +08:00
Mr Chen 5b2839515b update 2018-12-28 18:11:01 +08:00
Mr Chen 392ab0e8cd simdht 2018-12-28 17:50:22 +08:00
Mr Chen e1f9aeb065 update 2018-12-28 17:33:20 +08:00
Mr Chen 7bb412a0bd update 2018-12-28 17:02:38 +08:00
Mr Chen f67d9e088e update 2018-12-28 16:33:37 +08:00
Mr Chen ee7c42481f Update crontab.js 2018-12-28 14:18:15 +08:00
Mr Chen f7a764d6a4 update 2018-12-28 14:08:49 +08:00
Mr Chen d8ab3c2511 update 2018-12-28 13:15:03 +08:00
Mr Chen a36c619f23 Update __init__.py 2018-12-28 13:07:21 +08:00
Mr Chen 1280c993fd Update login.html 2018-12-28 13:06:07 +08:00
Mr Chen b433042a87 update 2018-12-28 11:40:21 +08:00
Mr Chen 62cb495ee0 update 2018-12-28 11:31:08 +08:00
Mr Chen feb91ce0b9 Update system_api.py 2018-12-28 11:12:50 +08:00
Mr Chen 48b123ae17 update 2018-12-28 10:49:15 +08:00
midoks 45374c8e65 u 2018-12-27 23:16:12 +08:00
Mr Chen 3e9c884d83 update 2018-12-27 19:38:15 +08:00
Mr Chen 501c35f1f6 Update index.py 2018-12-27 19:17:18 +08:00
Mr Chen 895bf541e2 Update install.sh 2018-12-27 19:14:54 +08:00
Mr Chen 58b7cd5193 update 2018-12-27 19:14:18 +08:00
Mr Chen 05184e5608 Update index.py 2018-12-27 19:11:08 +08:00
Mr Chen da05ef9b15 Update index.py 2018-12-27 19:00:15 +08:00
Mr Chen 5ef627e490 update 2018-12-27 18:15:31 +08:00
Mr Chen d0e5ff7461 update 2018-12-27 17:22:11 +08:00
Mr Chen 8b8533e820 Update www.conf 2018-12-27 16:06:39 +08:00
Mr Chen c6d591100f Update commit.tpl 2018-12-27 15:22:51 +08:00
Mr Chen cfe5463d87 Update commit.tpl 2018-12-27 15:14:19 +08:00
Mr Chen 8825d01455 Update commit.tpl 2018-12-27 15:03:21 +08:00
Mr Chen 57f2174764 Update install.sh 2018-12-27 14:42:04 +08:00
Mr Chen cc430c30ef up 2018-12-27 14:32:00 +08:00
Mr Chen 3d150074fb update 2018-12-26 21:02:29 +08:00
Mr Chen 5263efbbac Update install.sh 2018-12-26 20:33:25 +08:00
Mr Chen d26c529a3a Update commit.tpl 2018-12-26 20:28:22 +08:00
Mr Chen 897f3ddfe6 Update csvn.js 2018-12-26 20:06:06 +08:00
Mr Chen 606fc44641 Update gae.js 2018-12-26 20:04:41 +08:00
Mr Chen c49bed0474 Update index.py 2018-12-26 19:57:51 +08:00
Mr Chen c92f110893 Update index.py 2018-12-26 19:47:14 +08:00
Mr Chen be526ccd4e Update gae.js 2018-12-26 18:14:28 +08:00
Mr Chen 31d4fef0ee Update index.py 2018-12-26 18:10:20 +08:00
Mr Chen f28784db54 update 2018-12-26 18:04:57 +08:00
Mr Chen 6ca67961fb update 2018-12-26 15:57:26 +08:00
Mr Chen b367c45dd6 update 2018-12-26 15:10:29 +08:00
Mr Chen 10661e4f14 update 2018-12-26 14:20:27 +08:00
Mr Chen 684f80bec9 Update csvn.js 2018-12-26 14:20:10 +08:00
Mr Chen 5523488b4c Update gae.js 2018-12-26 13:57:00 +08:00
Mr Chen c793e73d5d update 2018-12-26 12:38:13 +08:00
Mr Chen 6f8bc6d012 Update ico.png 2018-12-26 10:22:53 +08:00
Mr Chen db9fcd952c Update crontab_api.py 2018-12-26 10:08:22 +08:00
Mr Chen fdfd90a7e5 Update requirements.txt 2018-12-26 10:08:18 +08:00
midoks 2c2a50f301 Update __init__.py 2018-12-25 23:48:29 +08:00
Mr Chen a96d0b7401 update 2018-12-25 17:43:28 +08:00
Mr Chen d8362d1341 update 2018-12-25 17:37:08 +08:00
Mr Chen b97a14638f Update system_api.py 2018-12-25 16:58:25 +08:00
Mr Chen 3e705b02cf update 2018-12-25 16:56:57 +08:00
Mr Chen 4df0859734 update 2018-12-25 15:41:46 +08:00
Mr Chen 4c8022d47b update 2018-12-25 15:12:59 +08:00
Mr Chen 21d7ab3406 update 2018-12-25 14:30:51 +08:00
Mr Chen 9dd1c46521 Update __init__.py 2018-12-25 11:26:46 +08:00
Mr Chen 438cfb6256 Update __init__.py 2018-12-25 11:21:20 +08:00
Mr Chen a2bda07cc6 update 2018-12-25 10:52:39 +08:00
Mr Chen 9615fb2203 Update config.py 2018-12-25 10:09:33 +08:00
Mr Chen 49c181c577 Update cli.sh 2018-12-25 10:07:16 +08:00
midoks 0fa5e4fb48 update 2018-12-24 22:33:49 +08:00
Mr Chen 8e7130c382 Update app.py 2018-12-24 15:38:55 +08:00
Mr Chen 33c1ac82c8 Update index.html 2018-12-24 11:48:07 +08:00
Mr Chen df5aec2e8f Update install.sh 2018-12-24 11:37:53 +08:00
Mr Chen 6c864177ee Update install.sh 2018-12-24 11:37:35 +08:00
Mr Chen 9ee09b0e7d update 2018-12-24 11:14:51 +08:00
Mr Chen b7da91f92b update 2018-12-21 11:44:38 +08:00
Mr Chen 17e6703c07 Update site.js 2018-12-21 10:52:21 +08:00
Mr Chen a5f77a37f2 Update mw.tpl 2018-12-21 10:07:24 +08:00
midoks 78fc9fd90f u 2018-12-20 23:41:26 +08:00
midoks 700f042033 防盗链 ok 2018-12-20 22:30:00 +08:00
midoks e44768e608 update 2018-12-20 21:45:09 +08:00
midoks 2acef86207 Update config.py 2018-12-20 21:35:49 +08:00
midoks 6256bb02da Update cli.sh 2018-12-20 21:34:52 +08:00
midoks 04f5a27492 Update system_api.py 2018-12-20 21:34:47 +08:00
Mr Chen 7cd476696a Update site.js 2018-12-20 19:28:47 +08:00
Mr Chen 2ecaf0e2a3 update 2018-12-20 19:22:33 +08:00
Mr Chen c5d3494a94 update 2018-12-20 14:15:13 +08:00
Mr Chen af0658fd41 update 2018-12-20 14:05:57 +08:00
Mr Chen cccbd88145 站点添加优化 2018-12-20 13:39:43 +08:00
Mr Chen 48aad5b248 Update index.py 2018-12-20 13:29:05 +08:00
Mr Chen d843213c39 流量控制功能ok 2018-12-20 13:27:50 +08:00
Mr Chen 7ad33c5c59 update 2018-12-20 11:12:39 +08:00
Mr Chen ee56cfe5ab Update README.md 2018-12-20 11:07:36 +08:00
Mr Chen c6b38aa996 update 2018-12-20 10:45:43 +08:00
midoks c5205c2d55 文件保存 2018-12-20 00:48:41 +08:00
midoks 1be07f96ff Update install.sh 2018-12-20 00:26:07 +08:00
midoks 9f4af88c1e update 2018-12-19 23:37:31 +08:00
Mr Chen ebc0559dff up 2018-12-19 20:43:33 +08:00
Mr Chen fe320ecd3b phpinfo ok 2018-12-19 17:17:07 +08:00
Mr Chen 02c06e7ff1 update 2018-12-19 16:50:15 +08:00
Mr Chen 6d90d6fde5 update 2018-12-19 15:50:07 +08:00
Mr Chen bfc0b9efa3 update 2018-12-19 15:41:00 +08:00
Mr Chen 6e4e7bcf68 update 2018-12-19 15:21:31 +08:00
Mr Chen 5da505084d update 2018-12-19 13:54:19 +08:00
Mr Chen f19df17ef5 update 2018-12-19 10:42:37 +08:00
Mr Chen d99e89744d Update index.py 2018-12-19 10:34:18 +08:00
midoks 9695fe4b9b Update index.py 2018-12-18 23:22:08 +08:00
Mr Chen 5907dc36c5 Update index.py 2018-12-18 19:50:57 +08:00
Mr Chen d694af9358 update 2018-12-18 19:43:41 +08:00
Mr Chen 4dc2828c59 update 2018-12-18 19:37:46 +08:00
Mr Chen 37519b4c92 超时限制,上传限制 2018-12-18 18:09:54 +08:00
Mr Chen 90999c7ae1 u 2018-12-18 15:37:02 +08:00
Mr Chen f16d9ea269 update 2018-12-18 15:23:48 +08:00
Mr Chen 86098541e0 PHP update 2018-12-18 15:13:33 +08:00
Mr Chen 9ef04a4d9e Create php.ini 2018-12-18 15:13:22 +08:00
Mr Chen 752f8fae5a Update csvn.js 2018-12-18 15:13:19 +08:00
Mr Chen c5fdecf459 up 2018-12-18 13:43:24 +08:00
Mr Chen 19284cd5ef update 2018-12-18 13:17:37 +08:00
Mr Chen da92ab1c89 update 2018-12-18 10:38:46 +08:00
midoks 18ca47e8b3 up 2018-12-17 23:26:00 +08:00
midoks 8b624297ba Update site_api.py 2018-12-17 21:40:08 +08:00
midoks f0d9ff2ae9 Update cli.sh 2018-12-17 21:38:15 +08:00
midoks 21b2c17220 Update site_api.py 2018-12-17 21:38:11 +08:00
midoks 0df898a7d9 Update install.sh 2018-12-17 21:38:08 +08:00
midoks cf1f4c8538 Update default.sql 2018-12-17 21:35:13 +08:00
Mr Chen 89ecdcd29a update 2018-12-17 19:17:51 +08:00
Mr Chen 0c8fa5e616 Update site.py 2018-12-17 18:21:06 +08:00
Mr Chen f9252da1b0 update 2018-12-17 18:16:59 +08:00
Mr Chen e31cbad7dd update 2018-12-17 17:21:33 +08:00
Mr Chen 5bed9f0802 update 2018-12-17 16:47:40 +08:00
Mr Chen 1ae4b54779 update 2018-12-17 15:20:30 +08:00
Mr Chen 2b2a75adf0 Update openresty.js 2018-12-17 11:23:05 +08:00
Mr Chen 55184341d7 Update install.sh 2018-12-17 11:17:58 +08:00
Mr Chen 6504decc30 update 2018-12-17 11:11:33 +08:00
Mr Chen 843d798b91 update 2018-12-17 11:06:58 +08:00
midoks 087a6b4809 update 2018-12-16 23:29:35 +08:00
midoks 44438bd9aa Update install.sh 2018-12-15 11:18:33 +08:00
midoks c33cba0e85 update 2018-12-15 01:22:00 +08:00
midoks cdc3c95367 update 2018-12-14 23:29:47 +08:00
midoks 222cebe1b3 update 2018-12-14 21:53:33 +08:00
midoks 2fc2eff97e Update install.sh 2018-12-14 21:35:59 +08:00
midoks 79f8baeeb3 update 2018-12-14 21:35:55 +08:00
midoks 0399219df6 Update pick_filter.txt 2018-12-14 21:34:13 +08:00
midoks cd0d5ede16 Update pick_filter.txt 2018-12-14 21:31:58 +08:00
Mr Chen 1e6d1c6127 Update info.json 2018-12-14 19:21:23 +08:00
Mr Chen ff87dbe258 Update index.py 2018-12-14 18:38:27 +08:00
Mr Chen 7d6ddb40db update 2018-12-14 18:29:53 +08:00
Mr Chen 1cb57d3f65 update 2018-12-14 18:04:50 +08:00
Mr Chen 9ed434d274 update 2018-12-14 17:39:47 +08:00
Mr Chen f532a376a7 update 2018-12-14 16:06:59 +08:00
Mr Chen 4405f7720b Update info.json 2018-12-14 15:20:16 +08:00
Mr Chen fbde4aab88 Update commit.tpl 2018-12-14 15:20:11 +08:00
Mr Chen 864691d357 同步数据处理 2018-12-14 14:52:33 +08:00
Mr Chen 95bf0cb1e8 修正权限格式 2018-12-14 13:56:16 +08:00
midoks 126f2d553d Update index.py 2018-12-13 23:17:49 +08:00
midoks 2fb88be080 update 2018-12-13 23:15:33 +08:00
midoks fa307cdb49 Update commit.tpl 2018-12-13 23:05:55 +08:00
midoks 0850b6ed44 Update index.py 2018-12-13 22:52:20 +08:00
midoks ec1e99f9ca Update index.py 2018-12-13 22:47:45 +08:00
midoks 546dc4d7eb Update index.py 2018-12-13 22:45:16 +08:00
midoks 9b0b4ac305 Update index.py 2018-12-13 22:40:37 +08:00
midoks 23a1f3936d update 2018-12-13 22:37:27 +08:00
Mr Chen 4cb22a1e35 update 2018-12-13 20:01:29 +08:00
Mr Chen 3e3cdbe18c update 2018-12-13 18:20:27 +08:00
Mr Chen bdc46d9401 Update pick_filter.txt 2018-12-13 18:08:55 +08:00
Mr Chen 64986dd125 gogs ready 2018-12-13 18:07:44 +08:00
Mr Chen 7ee00ab0b5 Update csvn.js 2018-12-13 17:13:48 +08:00
Mr Chen 488d92ba19 update 2018-12-13 17:09:23 +08:00
Mr Chen 9cebfb64cb 查找更新 2018-12-13 15:36:19 +08:00
Mr Chen 7800429f8d update 2018-12-13 15:20:47 +08:00
Mr Chen 7954714bb7 update 2018-12-13 14:57:30 +08:00
Mr Chen 1d396b73f0 Update index.html 2018-12-13 14:37:49 +08:00
Mr Chen 5f95a1d56a update 2018-12-13 14:37:38 +08:00
Mr Chen 51951a2685 update 2018-12-13 14:37:31 +08:00
Mr Chen 737453600d Update csvn.js 2018-12-13 13:51:14 +08:00
Mr Chen 17ef460f4c update 2018-12-13 13:34:06 +08:00
Mr Chen 38be955738 add debug 2018-12-13 12:56:06 +08:00
Mr Chen daf5c7c2b0 Update pick_filter.txt 2018-12-13 12:51:22 +08:00
Mr Chen acdb35f395 Update install.sh 2018-12-13 11:14:54 +08:00
midoks 5e8a15c230 update 2018-12-13 01:28:54 +08:00
midoks 34bcdd915c Update setting.py 2018-12-13 01:14:25 +08:00
midoks aa718adfea Update setting.py 2018-12-13 01:10:07 +08:00
midoks 936592661b update 2018-12-13 01:09:38 +08:00
midoks c740b4affb Update config.py 2018-12-13 00:54:13 +08:00
midoks 042b07efa2 Update csvn.js 2018-12-13 00:49:11 +08:00
midoks 6a6d22fd2d Update index.py 2018-12-12 23:37:11 +08:00
midoks f99502d2c8 Update config.py 2018-12-12 21:57:24 +08:00
midoks 1cf41348b7 Update config.py 2018-12-12 21:40:24 +08:00
midoks acdb226df9 update 2018-12-12 21:35:04 +08:00
Mr Chen 6259f21196 update 2018-12-12 19:30:42 +08:00
Mr Chen 6ad1292003 Update task.py 2018-12-12 19:26:28 +08:00
Mr Chen a682ba3e43 Update mw.tpl 2018-12-12 19:21:44 +08:00
Mr Chen 7509b259e7 Update setting.py 2018-12-12 18:47:42 +08:00
Mr Chen 8d170d87e4 update 2018-12-12 18:45:33 +08:00
Mr Chen bc4e5f6a87 update 2018-12-12 18:06:02 +08:00
Mr Chen 954f66c8dc update 2018-12-12 15:11:55 +08:00
Mr Chen a7f860de2b Update index.py 2018-12-12 14:06:10 +08:00
Mr Chen 6e7e291da3 update 2018-12-12 13:57:43 +08:00
Mr Chen 2bca78c32d update 2018-12-12 10:31:01 +08:00
midoks fb4311cdbf update 2018-12-12 00:07:01 +08:00
Mr Chen d889bf2cf3 Update index.py 2018-12-11 19:51:01 +08:00
Mr Chen 511a7ac12b Update index.py 2018-12-11 19:30:02 +08:00
Mr Chen 03e126cb48 Update index.py 2018-12-11 17:56:05 +08:00
Mr Chen 2acbe56e21 update 2018-12-11 17:53:37 +08:00
Mr Chen 8425aa4942 update 2018-12-11 14:49:26 +08:00
Mr Chen 17ad9abe6b update 2018-12-11 14:25:12 +08:00
Mr Chen 11166bbab1 Update files.py 2018-12-11 13:54:50 +08:00
Mr Chen f5f3f7ded5 update 2018-12-11 13:46:27 +08:00
Mr Chen 26bae283be update 2018-12-11 13:29:27 +08:00
Mr Chen bfb12692a6 Update csvn.js 2018-12-11 11:01:28 +08:00
Mr Chen 6bc6f17783 Update csvn.js 2018-12-11 10:37:45 +08:00
Mr Chen cd6f86ebfa Update csvn.js 2018-12-11 10:34:20 +08:00
Mr Chen 5abb2613a1 update 2018-12-11 10:31:53 +08:00
midoks a08dee242a Update csvn.js 2018-12-11 01:17:09 +08:00
midoks 2700b6b67b Update csvn.js 2018-12-11 01:15:09 +08:00
midoks e41148d72d Update index.py 2018-12-11 00:46:36 +08:00
midoks 9b5c80bc72 Update csvn.js 2018-12-11 00:44:29 +08:00
midoks 958755d18d update 2018-12-11 00:28:09 +08:00
Mr Chen 9af7e0f95b up 2018-12-10 19:37:38 +08:00
Mr Chen 90e86cda0d update 2018-12-10 19:17:40 +08:00
Mr Chen ea2ed9d003 Update crontab.html 2018-12-10 17:35:46 +08:00
Mr Chen 67eb3590c7 update 2018-12-10 17:27:09 +08:00
Mr Chen e66afbbb2d Update index.py 2018-12-10 16:41:01 +08:00
Mr Chen f959391b85 Create mw.sh 2018-12-10 16:29:04 +08:00
Mr Chen 663e95288a update 2018-12-10 16:18:35 +08:00
Mr Chen 0af3c7622d update 2018-12-10 15:53:06 +08:00
Mr Chen 40e2186a5b update 2018-12-10 15:32:31 +08:00
Mr Chen 121c972951 优化显示 2018-12-10 15:10:07 +08:00
Mr Chen 229cb977a1 update 2018-12-10 14:22:22 +08:00
Mr Chen ae845a702c u 2018-12-10 13:12:33 +08:00
Mr Chen 35b0b1d153 Update public.js 2018-12-10 11:43:20 +08:00
Mr Chen 4801850373 openresty error_logs 2018-12-10 11:42:13 +08:00
Mr Chen 8b3d0cbba4 update 2018-12-10 10:45:30 +08:00
Mr Chen 4f580d0427 update 2018-12-10 10:44:54 +08:00
Mr Chen 2f794c5b73 update 2018-12-10 10:33:03 +08:00
midoks 21cd34d272 Update index.html 2018-12-09 23:30:57 +08:00
midoks c58e1f7278 Update index.py 2018-12-09 23:30:54 +08:00
midoks 5b49f24a8d Update php56.tpl 2018-12-09 23:30:52 +08:00
midoks ce89a2a275 Update php.js 2018-12-09 23:30:50 +08:00
midoks 35f905e94c Update public.js 2018-12-09 23:30:46 +08:00
midoks 1c431286e4 Update index.py 2018-12-09 21:23:56 +08:00
midoks 705cef730b Update public.js 2018-12-09 20:33:16 +08:00
midoks 2a5da5593b Update soft.js 2018-12-09 20:33:14 +08:00
midoks 22692d8ed4 Update index.py 2018-12-09 20:31:39 +08:00
midoks 5cdae707e9 Create php56.tpl 2018-12-09 20:31:31 +08:00
midoks 5be9f1ae66 Update public.js 2018-12-09 20:31:28 +08:00
midoks ba931a0c2a Update index.py 2018-12-09 19:10:14 +08:00
midoks 5b87572bff up 2018-12-09 18:58:41 +08:00
midoks d51de312ac Update index.py 2018-12-09 14:07:13 +08:00
midoks bcd2e7298b update 2018-12-09 13:37:52 +08:00
midoks a985511b3b Update index.py 2018-12-09 13:28:36 +08:00
midoks abb9fb72f0 Update index.py 2018-12-09 13:23:37 +08:00
midoks b36ad3a595 Update index.py 2018-12-09 13:20:05 +08:00
midoks a118f33f57 Update index.py 2018-12-09 13:17:15 +08:00
midoks 58b888edcd Update index.py 2018-12-09 13:06:15 +08:00
midoks 43d906139e Update index.py 2018-12-09 13:00:18 +08:00
midoks b91bc040d4 Update index.py 2018-12-09 12:59:36 +08:00
midoks c6eba5bbf1 Update index.py 2018-12-09 12:52:41 +08:00
midoks 1adbf733d8 Update index.py 2018-12-09 12:50:30 +08:00
midoks 913d483e63 Update index.py 2018-12-09 12:40:43 +08:00
midoks 9951f7151e Update index.py 2018-12-09 12:37:49 +08:00
midoks 167a386a0d update 2018-12-09 11:59:00 +08:00
midoks 5473ee74cb Update install.sh 2018-12-09 11:43:57 +08:00
midoks dbeefc06c8 update 2018-12-09 11:42:11 +08:00
midoks 444730e553 Update install.sh 2018-12-09 11:36:18 +08:00
midoks 8a2e17198e Update index.py 2018-12-09 11:16:32 +08:00
midoks bc41788d49 u 2018-12-08 23:26:34 +08:00
midoks ebd8e93b16 update 2018-12-08 23:02:58 +08:00
midoks a45994c3c7 update 2018-12-08 22:33:32 +08:00
midoks f41f616daf update 2018-12-08 17:30:58 +08:00
midoks da5b9351e2 Update install.sh 2018-12-08 17:19:17 +08:00
midoks 3c080e0264 Update index.py 2018-12-08 17:09:36 +08:00
midoks dc62aabfd4 Update index.html 2018-12-08 17:09:33 +08:00
midoks c6da2e56ee Create csvn.js 2018-12-08 17:09:30 +08:00
midoks 461f3dcb0a Update index.html 2018-12-08 17:09:25 +08:00
midoks ee5b9f35ad Update soft.js 2018-12-08 17:07:51 +08:00
midoks 3ad8496daf Update public.js 2018-12-08 16:49:37 +08:00
midoks 77023263a6 Update index.py 2018-12-08 16:25:45 +08:00
midoks 6497627931 update 2018-12-08 16:24:36 +08:00
midoks 2ae3426c82 Update index.py 2018-12-08 15:47:40 +08:00
midoks dbeb919f05 update 2018-12-08 14:43:32 +08:00
midoks 2106746f6c Delete phpfpm_status.conf 2018-12-08 14:43:21 +08:00
midoks 31d5b90670 公共js 2018-12-08 14:43:17 +08:00
midoks ceaf9c42db update 2018-12-08 12:42:02 +08:00
Mr Chen 9067778bf3 u 2018-12-07 19:12:18 +08:00
Mr Chen 99053b67ce 调整 2018-12-07 18:47:33 +08:00
Mr Chen 07b8d91f31 redis调整ok 2018-12-07 17:44:32 +08:00
Mr Chen e9d4e09049 Update index.py 2018-12-07 16:44:08 +08:00
Mr Chen 629416760f Update install.sh 2018-12-07 15:55:12 +08:00
Mr Chen d1ade4355e Update index.py 2018-12-07 15:52:40 +08:00
Mr Chen 4508e30ea7 加入自启动选项功能
1.memcached 调整ok
2018-12-07 15:49:59 +08:00
Mr Chen b1c5c90bef update 2018-12-07 14:18:30 +08:00
midoks e9a7db2c1d update 2018-12-06 23:29:41 +08:00
Mr Chen 63e5f26491 u 2018-12-06 19:49:54 +08:00
Mr Chen ed93ccc0ee Update plugin_api.py 2018-12-06 15:41:57 +08:00
midoks 929a50c137 up 2018-12-06 00:09:25 +08:00
Mr Chen fe87092750 Update soft.js 2018-12-05 20:26:38 +08:00
Mr Chen c144cead18 u 2018-12-05 20:15:00 +08:00
Mr Chen afdc9720fc u 2018-12-05 18:46:45 +08:00
Mr Chen 194c7b9d45 Delete control.conf 2018-12-05 18:45:57 +08:00
Mr Chen 162557230a u 2018-12-05 17:35:24 +08:00
Mr Chen f4dfe502cb u 2018-12-05 17:34:32 +08:00
Mr Chen 7a3d49a9cf u 2018-12-05 17:04:20 +08:00
Mr Chen 49f1407c42 u 2018-12-05 16:24:39 +08:00
Mr Chen 319f72865d Update install.sh 2018-12-05 15:13:28 +08:00
Mr Chen 0eaa6f38e0 update 2018-12-05 14:56:50 +08:00
Mr Chen eeef8d488c Update info.json 2018-12-05 14:20:34 +08:00
Mr Chen 4e69f9540a u 2018-12-05 14:12:10 +08:00
Mr Chen a0e8d75af7 u 2018-12-05 14:00:31 +08:00
Mr Chen f54f7d4ce3 Update soft.js 2018-12-05 11:22:38 +08:00
Mr Chen 5f4893c115 u 2018-12-05 11:18:31 +08:00
Mr Chen a48b869fe9 abkill 2018-12-05 11:15:06 +08:00
Mr Chen 266a8cf806 up 2018-12-05 11:09:48 +08:00
Mr Chen 13e4dcf8ad u 2018-12-05 11:01:25 +08:00
Mr Chen 1ca469518d csvn update 2018-12-05 10:36:41 +08:00
midoks 4284a3daf4 Update site.html 2018-12-04 23:35:33 +08:00
midoks 84995650ee Update task.py 2018-12-04 23:16:47 +08:00
midoks fa662d75d6 update 2018-12-04 23:15:00 +08:00
Mr Chen 842c0daf70 up 2018-12-04 19:38:27 +08:00
Mr Chen 798608287e Update info.json 2018-12-04 19:22:10 +08:00
Mr Chen 437225374e u 2018-12-04 19:20:54 +08:00
Mr Chen 3a442570db Update system_api.py 2018-12-04 19:19:26 +08:00
Mr Chen 366c3677c2 u 2018-12-04 18:55:42 +08:00
Mr Chen 6dcf1db856 u 2018-12-04 18:55:27 +08:00
Mr Chen b3ca295e51 Update info.json 2018-12-04 13:59:48 +08:00
Mr Chen 03f06ee384 Update .gitignore 2018-12-04 13:56:47 +08:00
Mr Chen 2dc96cd04e u 2018-12-04 13:38:08 +08:00
Mr Chen a875293116 u 2018-12-04 13:26:58 +08:00
Mr Chen 8735fb9238 u 2018-12-04 13:22:22 +08:00
Mr Chen 58fcf0e8f9 Update install.sh 2018-12-04 13:13:36 +08:00
Mr Chen fccc30ebb1 Update system_api.py 2018-12-04 13:05:15 +08:00
Mr Chen 6b9da57ff2 u 2018-12-03 19:37:46 +08:00
Mr Chen cd6b2ad65e 代码打包 2018-12-03 18:22:04 +08:00
Mr Chen 60b2834adf Update system_api.py 2018-12-03 18:03:28 +08:00
Mr Chen c74e0428fd Update info.json 2018-12-03 17:57:08 +08:00
Mr Chen 20d486629e u 2018-12-03 17:52:11 +08:00
Mr Chen f984e4ecc7 u 2018-12-03 17:50:43 +08:00
Mr Chen 0bdea14560 Update .gitignore 2018-12-03 17:24:57 +08:00
Mr Chen 0c3599facb u 2018-12-03 17:24:49 +08:00
Mr Chen 05eb434bf8 Update system_api.py 2018-12-03 16:44:35 +08:00
Mr Chen 12dccc1df0 u 2018-12-03 16:44:29 +08:00
Mr Chen 11e7316911 Update info.json 2018-12-03 14:24:40 +08:00
595 changed files with 37446 additions and 11027 deletions
+13 -4
View File
@@ -8,13 +8,11 @@ __pycache__/
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
@@ -108,5 +106,16 @@ venv.bak/
.idea/*.iml
tmp/*.pl
tmp/*.log
data/json/index.json
data/system.db
*.swp
*.zip
scripts/init.d/mw
logs/*
data/*.db
data/control.conf
data/iplist.txt
data/json/index.json
data/json/config.json
data/site.pl
data/admin_path.pl
data/close.pl
ssl/input.pl
+1 -1
View File
@@ -1,4 +1,4 @@
# mdweb
# mdserver-web
简单的Linux面板
### 自动安装
+4 -45
View File
@@ -3,53 +3,12 @@
import sys
import io
import os
import time
from datetime import timedelta
sys.path.append("/class/core/")
reload(sys)
sys.setdefaultencoding('utf8')
import route
from flask import Flask
app = Flask(__name__)
app.debug = True
DEFAULT_MODULES = (
(route.dashboard, "/"),
(route.site, "/site"),
(route.files, "/files"),
(route.soft, "/soft"),
(route.config, "/config"),
(route.plugins, "/plugins"),
(route.task, "/task"),
(route.system, "/system"),
(route.database, "/database"),
(route.crontab, "/crontab"),
(route.firewall, "/firewall"),
(route.control, "/control"),
)
# print "time.time(): %f " % time.time()
app.config.version = "0.0.1" + str(time.time())
app.config['SECRET_KEY'] = os.urandom(24)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
def setting_modules(app, modules):
for module, url_prefix in modules:
app.register_blueprint(module, url_prefix=url_prefix)
setting_modules(app, DEFAULT_MODULES)
from route import app, socketio
try:
if __name__ == "__main__":
app.run()
PORT = 7200
HOST = '0.0.0.0'
socketio.run(app, host=HOST, port=PORT)
except Exception as ex:
print ex
+81
View File
@@ -0,0 +1,81 @@
# coding: utf-8
import os
import sys
import time
import string
import json
import hashlib
import shlex
import datetime
import subprocess
import re
import hashlib
from random import Random
import public
import db
from flask import redirect
def init():
initDB()
initInitD()
initUserInfo()
def local():
result = checkClose()
if result:
return result
# 检查面板是否关闭
def checkClose():
if os.path.exists('data/close.pl'):
return redirect('/close')
def initDB():
try:
sql = db.Sql().dbfile('default')
csql = public.readFile('data/sql/default.sql')
csql_list = csql.split(';')
for index in range(len(csql_list)):
sql.execute(csql_list[index], ())
except Exception, ex:
print str(ex)
def initInitD():
script = public.getRunDir() + '/scripts/init.d/mw.tpl'
script_bin = public.getRunDir() + '/scripts/init.d/mw'
# if os.path.exists(script_bin):
# return
content = public.readFile(script)
content = content.replace("{$SERVER_PATH}", public.getRunDir())
public.writeFile(script_bin, content)
public.execShell('chmod +x ' + script_bin)
if not public.isAppleSystem():
initd_bin = '/etc/init.d/mw'
if not os.path.exists(initd_bin):
import shutil
shutil.copyfile(script_bin, initd_bin)
public.execShell('chmod +x ' + initd_bin)
def initUserInfo():
data = public.M('users').where('id=?', (1,)).getField('password')
if data == '21232f297a57a5a743894a0e4a801fc3':
pwd = public.getRandomString(8).lower()
file_pw = public.getRunDir() + '/data/default.pl'
public.writeFile(file_pw, pwd)
public.M('users').where('id=?', (1,)).setField(
'password', public.md5(pwd))
+320
View File
@@ -0,0 +1,320 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
from flask import session
from flask import request
class config_api:
__version = '0.0.5'
def __init__(self):
pass
##### ----- start ----- ###
# 取面板列表
def getPanelListApi(self):
data = public.M('panel').field(
'id,title,url,username,password,click,addtime').order('click desc').select()
return public.getJson(data)
def addPanelInfoApi(self):
title = request.form.get('title', '')
url = request.form.get('url', '')
username = request.form.get('username', '')
password = request.form.get('password', '')
# 校验是还是重复
isAdd = public.M('panel').where(
'title=? OR url=?', (title, url)).count()
if isAdd:
return public.returnJson(False, '备注或面板地址重复!')
isRe = public.M('panel').add('title,url,username,password,click,addtime',
(title, url, username, password, 0, int(time.time())))
if isRe:
return public.returnJson(True, '添加成功!')
return public.returnJson(False, '添加失败!')
# 删除面板资料
def delPanelInfoApi(self):
mid = request.form.get('id', '')
isExists = public.M('panel').where('id=?', (mid,)).count()
if not isExists:
return public.returnJson(False, '指定面板资料不存在!')
public.M('panel').where('id=?', (mid,)).delete()
return public.returnJson(True, '删除成功!')
# 修改面板资料
def setPanelInfoApi(self):
title = request.form.get('title', '')
url = request.form.get('url', '')
username = request.form.get('username', '')
password = request.form.get('password', '')
mid = request.form.get('id', '')
# 校验是还是重复
isSave = public.M('panel').where(
'(title=? OR url=?) AND id!=?', (title, url, mid)).count()
if isSave:
return public.returnMsg(False, '备注或面板地址重复!')
# 更新到数据库
isRe = public.M('panel').where('id=?', (mid,)).save(
'title,url,username,password', (title, url, username, password))
if isRe:
return public.returnMsg(True, '修改成功!')
return public.returnMsg(False, '修改失败!')
def syncDateApi(self):
if public.isAppleSystem():
return public.returnJson(True, '开发系统不必同步时间!')
data = public.execShell('ntpdate -s time.nist.gov')
if data[0] == '':
return public.returnJson(True, '同步成功!')
return public.returnJson(False, '同步失败:' + data[0])
def setPasswordApi(self):
password1 = request.form.get('password1', '')
password2 = request.form.get('password2', '')
if password1 != password2:
return public.returnJson(False, '两次输入的密码不一致,请重新输入!')
if len(password1) < 5:
return public.returnJson(False, '用户密码不能小于5位!')
public.M('users').where("username=?", (session['username'],)).setField(
'password', public.md5(password1.strip()))
return public.returnJson(True, '密码修改成功!')
def setNameApi(self):
name1 = request.form.get('name1', '')
name2 = request.form.get('name2', '')
if name1 != name2:
return public.returnJson(False, '两次输入的用户名不一致,请重新输入!')
if len(name1) < 3:
return public.returnJson(False, '用户名长度不能少于3位')
public.M('users').where("username=?", (session['username'],)).setField(
'username', name1.strip())
session['username'] = name1
return public.returnJson(True, '用户修改成功!')
def setApi(self):
webname = request.form.get('webname', '')
port = request.form.get('port', '')
host_ip = request.form.get('host_ip', '')
domain = request.form.get('domain', '')
sites_path = request.form.get('sites_path', '')
backup_path = request.form.get('backup_path', '')
if domain != '':
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return public.returnJson(False, '主域名格式不正确')
if int(port) >= 65535 or int(port) < 100:
return public.returnJson(False, '端口范围不正确!')
if webname != public.getConfig('title'):
public.setConfig('title', webname)
if sites_path != public.getWwwDir():
public.setWwwDir(sites_path)
if backup_path != public.getWwwDir():
public.setBackupDir(backup_path)
if port != public.getHostPort():
import system_api
public.setHostPort(port)
system_api.system_api().restartMw()
if host_ip != public.getHostAddr():
public.setHostAddr(host_ip)
mhost = public.getHostAddr()
info = {
'uri': '/config',
'host': mhost + ':' + port
}
return public.returnJson(True, '保存成功!', info)
def setAdminPathApi(self):
admin_path = request.form.get('admin_path', '').strip()
admin_path_checks = ['/', '/close', '/login', '/do_login', '/site',
'/sites', '/download_file', '/control', '/crontab',
'/firewall', '/files', 'config', '/soft', '/system',
'/code', '/ssl', '/plugins']
if admin_path == '':
admin_path = '/'
if admin_path != '/':
if len(admin_path) < 6:
return public.returnJson(False, '安全入口地址长度不能小于6位!')
if admin_path in admin_path_checks:
return public.returnJson(False, '该入口已被面板占用,请使用其它入口!')
if not re.match("^/[\w\./-_]+$", admin_path):
return public.returnJson(False, '入口地址格式不正确,示例: /my_panel')
else:
domain = public.readFile('data/domain.conf')
if not domain:
domain = ''
limitip = public.readFile('data/limitip.conf')
if not limitip:
limitip = ''
if not domain.strip() and not limitip.strip():
return public.returnJson(False, '警告,关闭安全入口等于直接暴露你的后台地址在外网,十分危险,至少开启以下一种安全方式才能关闭:<a style="color:red;"><br>1、绑定访问域名<br>2、绑定授权IP</a>')
admin_path_file = 'data/admin_path.pl'
admin_path_old = '/'
if os.path.exists(admin_path_file):
admin_path_old = public.readFile(admin_path_file).strip()
if admin_path_old != admin_path:
public.writeFile(admin_path_file, admin_path)
public.restartMw()
return public.returnJson(True, '修改成功!')
def closePanelApi(self):
filename = 'data/close.pl'
if os.path.exists(filename):
os.remove(filename)
return public.returnJson(True, '开启成功')
public.writeFile(filename, 'True')
public.execShell("chmod 600 " + filename)
public.execShell("chown root.root " + filename)
return public.returnJson(True, '面板已关闭!')
def setIpv6StatusApi(self):
ipv6_file = 'data/ipv6.pl'
if os.path.exists('data/ipv6.pl'):
os.remove(ipv6_file)
public.writeLog('面板设置', '关闭面板IPv6兼容!')
else:
public.writeFile(ipv6_file, 'True')
public.writeLog('面板设置', '开启面板IPv6兼容!')
public.restartMw()
return public.returnJson(True, '设置成功!')
# 获取面板证书
def getPanelSslApi(self):
cert = {}
cert['privateKey'] = public.readFile('ssl/privateKey.pem')
cert['certPem'] = public.readFile('ssl/certificate.pem')
cert['rep'] = os.path.exists('ssl/input.pl')
return public.getJson(cert)
# 保存面板证书
def savePanelSslApi(self):
keyPath = 'ssl/privateKey.pem'
certPath = 'ssl/certificate.pem'
checkCert = '/tmp/cert.pl'
certPem = request.form.get('certPem', '').strip()
privateKey = request.form.get('privateKey', '').strip()
public.writeFile(checkCert, certPem)
if privateKey:
public.writeFile(keyPath, privateKey)
if certPem:
public.writeFile(certPath, certPem)
if not public.checkCert(checkCert):
return public.returnJson(False, '证书错误,请检查!')
public.writeFile('ssl/input.pl', 'True')
return public.returnJson(True, '证书已保存!')
# 设置面板SSL
def setPanelSslApi(self):
sslConf = public.getRunDir() + '/data/ssl.pl'
if os.path.exists(sslConf):
os.system('rm -f ' + sslConf)
return public.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
else:
os.system('pip install cffi==1.10')
os.system('pip install cryptography==2.1')
os.system('pip install pyOpenSSL==16.2')
try:
if not self.createSSL():
return public.returnJson(False, '开启失败,无法自动安装pyOpenSSL组件!<p>请尝试手动安装: pip install pyOpenSSL</p>')
public.writeFile(sslConf, 'True')
except Exception as ex:
return public.returnJson(False, '开启失败,无法自动安装pyOpenSSL组件!<p>请尝试手动安装: pip install pyOpenSSL</p>')
return public.returnJson(True, '开启成功,请使用https协议访问面板!')
def getApi(self):
data = {}
return public.getJson(data)
##### ----- end ----- ###
# 自签证书
def createSSL(self):
if os.path.exists('ssl/input.pl'):
return True
import OpenSSL
key = OpenSSL.crypto.PKey()
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
cert = OpenSSL.crypto.X509()
cert.set_serial_number(0)
cert.get_subject().CN = '120.27.27.98'
cert.set_issuer(cert.get_subject())
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(86400 * 3650)
cert.set_pubkey(key)
cert.sign(key, 'md5')
cert_ca = OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert)
private_key = OpenSSL.crypto.dump_privatekey(
OpenSSL.crypto.FILETYPE_PEM, key)
if len(cert_ca) > 100 and len(private_key) > 100:
public.writeFile('ssl/certificate.pem', cert_ca)
public.writeFile('ssl/privateKey.pem', private_key)
print cert_ca, private_key
return True
return False
def getVersion(self):
return self.__version
def get(self):
data = {}
data['title'] = public.getConfig('title')
data['site_path'] = public.getWwwDir()
data['backup_path'] = public.getBackupDir()
sformat = 'date +"%Y-%m-%d %H:%M:%S %Z %z"'
data['systemdate'] = public.execShell(sformat)[0].strip()
data['port'] = public.getHostPort()
data['ip'] = public.getHostAddr()
admin_path_file = 'data/admin_path.pl'
if not os.path.exists(admin_path_file):
data['admin_path'] = '/'
else:
data['admin_path'] = public.readFile(admin_path_file)
ipv6_file = 'data/ipv6.pl'
if os.path.exists('data/ipv6.pl'):
data['ipv6'] = 'checked'
else:
data['ipv6'] = ''
ssl_file = 'data/ssl.pl'
if os.path.exists('data/ssl.pl'):
data['ssl'] = 'checked'
else:
data['ssl'] = ''
data['site_count'] = public.M('sites').count()
data['username'] = public.M('users').where(
"id=?", (1,)).getField('username')
return data
+514
View File
@@ -0,0 +1,514 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
from flask import request
class crontab_api:
field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress'
def __init__(self):
pass
##### ----- start ----- ###
def listApi(self):
_list = public.M('crontab').where('', ()).field(self.field).limit(
'0,5').order('id desc').select()
data = []
for i in range(len(_list)):
tmp = _list[i]
if _list[i]['type'] == "day":
tmp['type'] = '每天'
tmp['cycle'] = public.getInfo('每天, {1}点{2}分 执行', (str(
_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "day-n":
tmp['type'] = public.getInfo(
'每{1}天', (str(_list[i]['where1']),))
tmp['cycle'] = public.getInfo('每隔{1}天, {2}点{3}分 执行', (str(
_list[i]['where1']), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "hour":
tmp['type'] = '每小时'
tmp['cycle'] = public.getInfo(
'每小时, 第{1}分钟 执行', (str(_list[i]['where_minute']),))
elif _list[i]['type'] == "hour-n":
tmp['type'] = public.getInfo(
'每{1}小时', (str(_list[i]['where1']),))
tmp['cycle'] = public.getInfo('每{1}小时, 第{2}分钟 执行', (str(
_list[i]['where1']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "minute-n":
tmp['type'] = public.getInfo(
'每{1}分钟', (str(_list[i]['where1']),))
tmp['cycle'] = public.getInfo(
'每隔{1}分钟执行', (str(_list[i]['where1']),))
elif _list[i]['type'] == "week":
tmp['type'] = '每周'
if not _list[i]['where1']:
_list[i]['where1'] = '0'
tmp['cycle'] = public.getInfo('每周{1}, {2}点{3}分执行', (self.toWeek(int(
_list[i]['where1'])), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "month":
tmp['type'] = '每月'
tmp['cycle'] = public.getInfo('每月, {1}日 {2}点{3}分执行', (str(_list[i]['where1']), str(
_list[i]['where_hour']), str(_list[i]['where_minute'])))
data.append(tmp)
_ret = {}
_ret['data'] = data
count = public.M('crontab').where('', ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'remind'
_ret['page'] = public.getPage(_page)
return public.getJson(_ret)
# 设置计划任务状态
def setCronStatusApi(self):
mid = request.form.get('id', '')
cronInfo = public.M('crontab').where(
'id=?', (mid,)).field(self.field).find()
status = 1
if cronInfo['status'] == status:
status = 0
self.removeForCrond(cronInfo['echo'])
else:
cronInfo['status'] = 1
self.syncToCrond(cronInfo)
public.M('crontab').where('id=?', (mid,)).setField('status', status)
public.writeLog(
'计划任务', '修改计划任务[' + cronInfo['name'] + ']状态为[' + str(status) + ']')
return public.returnJson(True, '设置成功')
# 获取指定任务数据
def getCrondFindApi(self):
sid = request.form.get('id', '')
data = public.M('crontab').where(
'id=?', (sid,)).field(self.field).find()
return public.getJson(data)
def modifyCrondApi(self):
sid = request.form.get('id', '')
iname = request.form.get('name', '')
field_type = request.form.get('type', '')
week = request.form.get('week', '')
where1 = request.form.get('where1', '')
hour = request.form.get('hour', '')
minute = request.form.get('minute', '')
save = request.form.get('save', '')
backup_to = request.form.get('backup_to', '')
stype = request.form.get('stype', '')
sname = request.form.get('sname', '')
sbody = request.form.get('sbody', '')
urladdress = request.form.get('urladdress', '')
if len(iname) < 1:
return public.returnJson(False, '任务名称不能为空!')
params = {
'name': iname,
'type': field_type,
'week': week,
'where1': where1,
'hour': hour,
'minute': minute,
'save': save,
'backup_to': backup_to,
'stype': stype,
'sname': sname,
'sbody': sbody,
'urladdress': urladdress,
}
cuonConfig, get, name = self.getCrondCycle(params)
cronInfo = public.M('crontab').where(
'id=?', (sid,)).field(self.field).find()
del(cronInfo['id'])
del(cronInfo['addtime'])
cronInfo['name'] = get['name']
cronInfo['type'] = get['type']
cronInfo['where1'] = get['where1']
cronInfo['where_hour'] = get['hour']
cronInfo['where_minute'] = get['minute']
cronInfo['save'] = get['save']
cronInfo['backup_to'] = get['backup_to']
cronInfo['sbody'] = get['sbody']
cronInfo['urladdress'] = get['urladdress']
addData = public.M('crontab').where('id=?', (sid,)).save('name,type,where1,where_hour,where_minute,save,backup_to,sbody,urladdress', (get[
'name'], field_type, get['where1'], get['hour'], get['minute'], get['save'], get['backup_to'], get['sbody'], get['urladdress']))
self.removeForCrond(cronInfo['echo'])
self.syncToCrond(cronInfo)
public.writeLog('计划任务', '修改计划任务[' + cronInfo['name'] + ']成功')
return public.returnJson(True, '修改成功')
def logsApi(self):
sid = request.form.get('id', '')
echo = public.M('crontab').where("id=?", (sid,)).field('echo').find()
logFile = public.getServerDir() + '/cron/' + echo['echo'] + '.log'
if not os.path.exists(logFile):
return public.returnJson(False, '当前日志为空!')
log = public.getNumLines(logFile, 2000)
return public.returnJson(True, log)
def addApi(self):
iname = request.form.get('name', '')
field_type = request.form.get('type', '')
week = request.form.get('week', '')
where1 = request.form.get('where1', '')
hour = request.form.get('hour', '')
minute = request.form.get('minute', '')
save = request.form.get('save', '')
backup_to = request.form.get('backupTo', '')
stype = request.form.get('sType', '')
sname = request.form.get('sName', '')
sbody = request.form.get('sBody', '')
urladdress = request.form.get('urladdress', '')
if len(iname) < 1:
return public.returnJson(False, '任务名称不能为空!')
params = {
'name': iname,
'type': field_type,
'week': week,
'where1': where1,
'hour': hour,
'minute': minute,
'save': save,
'backup_to': backup_to,
'stype': stype,
'sname': sname,
'sbody': sbody,
'urladdress': urladdress,
}
# print params
cuonConfig, get, name = self.getCrondCycle(params)
cronPath = public.getServerDir() + '/cron'
cronName = self.getShell(params)
# print cuonConfig, _params, name
# print cronPath, cronName
# print stype
if type(cronName) == dict:
return cronName
cuonConfig += ' ' + cronPath + '/' + cronName + \
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
wRes = self.writeShell(cuonConfig)
if type(wRes) != bool:
return wRes
self.crondReload()
addData = public.M('crontab').add('name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress', (iname, field_type, where1, hour, minute, cronName, time.strftime(
'%Y-%m-%d %X', time.localtime()), 1, save, backup_to, stype, sname, sbody, urladdress))
if addData > 0:
return public.returnJson(True, '添加成功')
return public.returnJson(False, '添加失败')
def startTaskApi(self):
sid = request.form.get('id', '')
echo = public.M('crontab').where('id=?', (sid,)).getField('echo')
execstr = public.getServerDir() + '/cron/' + echo
os.system('chmod +x ' + execstr)
os.system('nohup ' + execstr + ' >> ' + execstr + '.log 2>&1 &')
return public.returnJson(True, '任务已执行!')
def delApi(self):
sid = request.form.get('id', '')
try:
find = public.M('crontab').where(
"id=?", (sid,)).field('name,echo').find()
if not self.removeForCrond(find['echo']):
return public.returnJson(False, '无法写入文件,请检查是否开启了系统加固功能!')
cronPath = public.getServerDir() + '/cron'
sfile = cronPath + '/' + find['echo']
if os.path.exists(sfile):
os.remove(sfile)
sfile = cronPath + '/' + find['echo'] + '.log'
if os.path.exists(sfile):
os.remove(sfile)
public.M('crontab').where("id=?", (sid,)).delete()
public.writeLog('计划任务', public.getInfo(
'删除计划任务[{1}]成功!', (find['name'],)))
return public.returnJson(True, '删除成功')
except Exception as e:
return public.returnJson(False, '删除失败:' + str(e))
def delLogsApi(self):
sid = request.form.get('id', '')
try:
echo = public.M('crontab').where("id=?", (sid,)).getField('echo')
logFile = public.getServerDir() + '/cron/' + echo + '.log'
os.remove(logFile)
return public.returnJson(True, '任务日志已清空!')
except:
return public.returnJson(False, '任务日志清空失败!')
# 取数据列表
def getDataListApi(self):
stype = request.form.get('type', '').encode('utf-8')
if stype == 'databases':
db_list = {}
db_list['orderOpt'] = []
path = public.getServerDir() + '/mysql'
if not os.path.exists(path + '/mysql.db'):
db_list['data'] = []
else:
db_list['data'] = public.M('databases').dbPos(
path, 'mysql').field('name,ps').select()
return public.getJson(db_list)
data = {}
data['data'] = public.M(stype).field('name,ps').select()
data['orderOpt'] = []
# try:
# tmp = public.readFile('data/libList.conf')
# libs = json.loads(tmp)
# import imp
# for lib in libs:
# imp.find_module(lib['module'])
# tmp = {}
# tmp['name'] = lib['name']
# tmp['value'] = lib['opt']
# data['orderOpt'].append(tmp)
# except Exception as e:
# print e
return public.getJson(data)
##### ----- start ----- ###
# 转换大写星期
def toWeek(self, num):
wheres = {
0: '日',
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六'
}
try:
return wheres[num]
except:
return ''
def getCrondCycle(self, params):
cuonConfig = ''
name = ''
if params['type'] == "day":
cuonConfig = self.getDay(params)
name = '每天'
elif params['type'] == "day-n":
cuonConfig = self.getDay_N(params)
name = public.getInfo('每{1}天', (params['where1'],))
elif params['type'] == "hour":
cuonConfig = self.getHour(params)
name = '每小时'
elif params['type'] == "hour-n":
cuonConfig = self.getHour_N(params)
name = '每小时'
elif params['type'] == "minute-n":
cuonConfig = self.minute_N(params)
elif params['type'] == "week":
params['where1'] = params['week']
cuonConfig = self.week(params)
elif params['type'] == "month":
cuonConfig = self.month(params)
return cuonConfig, params, name
# 取任务构造Day
def getDay(self, param):
cuonConfig = "{0} {1} * * * ".format(param['minute'], param['hour'])
return cuonConfig
# 取任务构造Day_n
def getDay_N(self, param):
cuonConfig = "{0} {1} */{2} * * ".format(
param['minute'], param['hour'], param['where1'])
return cuonConfig
# 取任务构造Hour
def getHour(self, param):
cuonConfig = "{0} * * * * ".format(param['minute'])
return cuonConfig
# 取任务构造Hour-N
def getHour_N(self, param):
cuonConfig = "{0} */{1} * * * ".format(
param['minute'], param['where1'])
return cuonConfig
# 取任务构造Minute-N
def minute_N(self, param):
cuonConfig = "*/{0} * * * * ".format(param['where1'])
return cuonConfig
# 取任务构造week
def week(self, param):
cuonConfig = "{0} {1} * * {2}".format(
param['minute'], param['hour'], param['week'])
return cuonConfig
# 取任务构造Month
def month(self, param):
cuonConfig = "{0} {1} {2} * * ".format(
param['minute'], param['hour'], param['where1'])
return cuonConfig
# 取执行脚本
def getShell(self, param):
# try:
stype = param['stype']
if stype == 'toFile':
shell = param.sFile
else:
head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
log = '.log'
wheres = {
'path': head + "python " + public.getServerDir() + "/mdserver-web/scripts/backup.py path " + param['sname'] + " " + str(param['save']),
'site': head + "python " + public.getServerDir() + "/mdserver-web/scripts/backup.py site " + param['sname'] + " " + str(param['save']),
'database': head + "python " + public.getServerDir() + "/mdserver-web/scripts/backup.py database " + param['sname'] + " " + str(param['save']),
'logs': head + "python " + public.getServerDir() + "/mdserver-web/scripts/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
'rememory': head + "/bin/bash " + public.getServerDir() + '/mdserver-web/scripts/rememory.sh'
}
if param['backup_to'] != 'localhost':
cfile = public.getServerDir() + "/mdserver-web/plugin/" + param[
'backup_to'] + "/" + param['backup_to'] + "_main.py"
if not os.path.exists(cfile):
cfile = public.getServerDir() + "/mdserver-web/script/backup_" + \
param['backup_to'] + ".py"
wheres = {
'path': head + "python " + cfile + " path " + param['sname'] + " " + str(param['save']),
'site': head + "python " + cfile + " site " + param['sname'] + " " + str(param['save']),
'database': head + "python " + cfile + " database " + param['sname'] + " " + str(param['save']),
'logs': head + "python " + public.getServerDir() + "/mdserver-web/scripts/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
'rememory': head + "/bin/bash " + public.getServerDir() + '/mdserver-web/scripts/rememory.sh'
}
try:
shell = wheres[stype]
except:
if stype == 'toUrl':
shell = head + "curl -sS --connect-timeout 10 -m 60 '" + \
param['urladdress'] + "'"
else:
shell = head + param['sbody'].replace("\r\n", "\n")
shell += '''
echo "----------------------------------------------------------------------------"
endDate=`date +"%Y-%m-%d %H:%M:%S"`
echo "★[$endDate] Successful"
echo "----------------------------------------------------------------------------"
'''
cronPath = public.getServerDir() + '/cron'
if not os.path.exists(cronPath):
public.execShell('mkdir -p ' + cronPath)
if not 'echo' in param:
cronName = public.md5(public.md5(str(time.time()) + '_mw'))
else:
cronName = param['echo']
file = cronPath + '/' + cronName
public.writeFile(file, self.checkScript(shell))
public.execShell('chmod 750 ' + file)
return cronName
# 检查脚本
def checkScript(self, shell):
keys = ['shutdown', 'init 0', 'mkfs', 'passwd',
'chpasswd', '--stdin', 'mkfs.ext', 'mke2fs']
for key in keys:
shell = shell.replace(key, '[***]')
return shell
# 将Shell脚本写到文件
def writeShell(self, config):
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/root'
if public.isAppleSystem():
file = '/etc/crontab'
else:
file = u_file
if not os.path.exists(file):
public.writeFile(file, '')
conf = public.readFile(file)
conf += config + "\n"
if public.writeFile(file, conf):
if not os.path.exists(u_file):
public.execShell("chmod 600 '" + file +
"' && chown root.root " + file)
else:
public.execShell("chmod 600 '" + file +
"' && chown root.crontab " + file)
return True
return public.returnJson(False, '文件写入失败,请检查是否开启系统加固功能!')
# 重载配置
def crondReload(self):
if public.isAppleSystem():
if os.path.exists('/etc/crontab'):
pass
# public.execShell('/usr/sbin/cron restart')
else:
if os.path.exists('/etc/init.d/crond'):
public.execShell('/etc/init.d/crond reload')
elif os.path.exists('/etc/init.d/cron'):
public.execShell('service cron restart')
else:
public.execShell("systemctl reload crond")
# 从crond删除
def removeForCrond(self, echo):
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/root'
if public.isAppleSystem():
file = '/etc/crontab'
else:
file = u_file
conf = public.readFile(file)
rep = ".+" + str(echo) + ".+\n"
conf = re.sub(rep, "", conf)
if not public.writeFile(file, conf):
return False
self.crondReload()
return True
def syncToCrond(self, cronInfo):
if 'status' in cronInfo:
if cronInfo['status'] == 0:
return False
if 'where_hour' in cronInfo:
cronInfo['hour'] = cronInfo['where_hour']
cronInfo['minute'] = cronInfo['where_minute']
cronInfo['week'] = cronInfo['where1']
cuonConfig, cronInfo, name = self.getCrondCycle(cronInfo)
cronPath = public.getServerDir() + '/cron'
cronName = self.getShell(cronInfo)
if type(cronName) == dict:
return cronName
cuonConfig += ' ' + cronPath + '/' + cronName + \
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
wRes = self.writeShell(cuonConfig)
if type(wRes) != bool:
return False
self.crondReload()
+5
View File
@@ -33,6 +33,10 @@ class Sql():
self.__DB_FILE = 'data/' + name + '.db'
return self
def dbPos(self, path, name):
self.__DB_FILE = path + '/' + name + '.db'
return self
def table(self, table):
# 设置表名
self.__DB_TABLE = table
@@ -223,6 +227,7 @@ class Sql():
def execute(self, sql, param):
# 执行SQL语句返回受影响行
self.__GetConn()
# print sql, param
try:
result = self.__DB_CONN.execute(sql, param)
self.__DB_CONN.commit()
+610
View File
@@ -0,0 +1,610 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
import shutil
from flask import request
from flask import send_file, send_from_directory
from flask import make_response
class files_api:
rPath = None
def __init__(self):
self.rPath = public.getRootDir() + '/recycle_bin/'
##### ----- start ----- ###
def getBodyApi(self):
path = request.form.get('path', '').encode('utf-8')
return self.getBody(path)
def getLastBodyApi(self):
path = request.form.get('path', '').encode('utf-8')
line = request.form.get('line', '100')
if not os.path.exists(path):
return public.returnJson(False, '文件不存在', (path,))
try:
data = public.getNumLines(path, int(line))
return public.returnJson(True, 'OK', data)
except Exception as ex:
return public.returnJson(False, u'无法正确读取文件!' + str(ex))
def saveBodyApi(self):
path = request.form.get('path', '').encode('utf-8')
data = request.form.get('data', '').encode('utf-8')
encoding = request.form.get('encoding', '').encode('utf-8')
return self.saveBody(path, data, encoding)
def downloadApi(self):
filename = request.args.get('filename', '').encode('utf-8')
if not os.path.exists(filename):
return ''
response = make_response(send_from_directory(
os.path.dirname(filename), os.path.basename(filename), as_attachment=True))
return response
def zipApi(self):
sfile = request.form.get('sfile', '').encode('utf-8')
dfile = request.form.get('dfile', '').encode('utf-8')
stype = request.form.get('type', '').encode('utf-8')
path = request.form.get('path', '').encode('utf-8')
return self.zip(sfile, dfile, stype, path)
def deleteApi(self):
path = request.form.get('path', '').encode('utf-8')
return self.delete(path)
def fileAccessApi(self):
filename = request.form.get('filename', '').encode('utf-8')
data = self.getAccess(filename)
return public.getJson(data)
def getDirSizeApi(self):
path = request.form.get('path', '').encode('utf-8')
tmp = self.getDirSize(path)
return public.returnJson(True, tmp[0].split()[0])
def getDirApi(self):
path = request.form.get('path', '').encode('utf-8')
if not os.path.exists(path):
path = public.getRootDir() + "/wwwroot"
search = request.args.get('search', '').strip().lower()
page = request.args.get('p', '1').strip().lower()
row = request.args.get('showRow', '10')
return self.getDir(path, int(page), int(row), search)
def createFileApi(self):
file = request.form.get('path', '').encode('utf-8')
try:
if not self.checkFileName(file):
return public.returnJson(False, '文件名中不能包含特殊字符!')
if os.path.exists(file):
return public.returnJson(False, '指定文件已存在!')
_path = os.path.dirname(file)
if not os.path.exists(_path):
os.makedirs(_path)
open(file, 'w+').close()
self.setFileAccept(file)
msg = public.getInfo('创建文件[{1}]成功!', (file,))
public.writeLog('文件管理', msg)
return public.returnJson(True, '文件创建成功!')
except Exception as e:
# print str(e)
return public.returnJson(True, '文件创建失败!')
def createDirApi(self):
path = request.form.get('path', '').encode('utf-8')
try:
if not self.checkFileName(path):
return public.returnJson(False, '目录名中不能包含特殊字符!')
if os.path.exists(path):
return public.returnJson(False, '指定目录已存在!')
os.makedirs(path)
self.setFileAccept(path)
msg = public.getInfo('创建目录[{1}]成功!', (path,))
public.writeLog('文件管理', msg)
return public.returnJson(True, '目录创建成功!')
except Exception as e:
return public.returnJson(False, '目录创建失败!')
def downloadFileApi(self):
import db
import time
url = request.form.get('url', '').encode('utf-8')
path = request.form.get('path', '').encode('utf-8')
filename = request.form.get('filename', '').encode('utf-8')
isTask = public.getRootDir() + '/tmp/panelTask.pl'
execstr = url + '|mw|' + path + '/' + filename
public.M('tasks').add('name,type,status,addtime,execstr',
('下载文件[' + filename + ']', 'download', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr))
public.writeFile(isTask, 'True')
# self.setFileAccept(path + '/' + filename)
return public.returnJson(True, '已将下载任务添加到队列!')
def removeTaskApi(self):
mid = request.form.get('id', '').encode('utf-8')
try:
name = public.M('tasks').where('id=?', (mid,)).getField('name')
status = public.M('tasks').where('id=?', (mid,)).getField('status')
public.M('tasks').delete(mid)
if status == '-1':
os.system(
"kill `ps -ef |grep 'python panelSafe.pyc'|grep -v grep|grep -v panelExec|awk '{print $2}'`")
os.system(
"kill `ps aux | grep 'python task.pyc$'|awk '{print $2}'`")
os.system('''
pids=`ps aux | grep 'sh'|grep -v grep|grep install|awk '{print $2}'`
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p
done
''')
os.system(
'rm -f ' + name.replace('扫描目录[', '').replace(']', '') + '/scan.pl')
isTask = public.getRootDir() + '/tmp/panelTask.pl'
public.writeFile(isTask, 'True')
os.system('/etc/init.d/mw start')
except:
os.system('/etc/init.d/mw start')
return public.returnJson(True, '任务已删除!')
# 上传文件
def uploadFileApi(self):
from werkzeug.utils import secure_filename
from flask import request
path = request.args.get('path', '').encode('utf-8')
if not os.path.exists(path):
os.makedirs(path)
f = request.files['zunfile']
filename = os.path.join(path, f.filename)
if sys.version_info[0] == 2:
filename = filename.encode('utf-8')
s_path = path
if os.path.exists(filename):
s_path = filename
p_stat = os.stat(s_path)
f.save(filename)
os.chown(filename, p_stat.st_uid, p_stat.st_gid)
os.chmod(filename, p_stat.st_mode)
msg = public.getInfo('上传文件[{1}] 到 [{2}]成功!', (filename, path))
public.writeLog('文件管理', msg)
return public.returnMsg(True, '上传成功!')
def getRecycleBinApi(self):
rPath = self.rPath
if not os.path.exists(rPath):
os.system('mkdir -p ' + rPath)
data = {}
data['dirs'] = []
data['files'] = []
data['status'] = os.path.exists('data/recycle_bin.pl')
data['status_db'] = os.path.exists('data/recycle_bin_db.pl')
for file in os.listdir(rPath):
try:
tmp = {}
fname = rPath + file
tmp1 = file.split('_mw_')
tmp2 = tmp1[len(tmp1) - 1].split('_t_')
tmp['rname'] = file
tmp['dname'] = file.replace('_mw_', '/').split('_t_')[0]
tmp['name'] = tmp2[0]
tmp['time'] = int(float(tmp2[1]))
if os.path.islink(fname):
filePath = os.readlink(fname)
link = ' -> ' + filePath
if os.path.exists(filePath):
tmp['size'] = os.path.getsize(filePath)
else:
tmp['size'] = 0
else:
tmp['size'] = os.path.getsize(fname)
if os.path.isdir(fname):
data['dirs'].append(tmp)
else:
data['files'].append(tmp)
except:
continue
return public.returnJson(True, 'OK', data)
# 回收站开关
def recycleBinApi(self):
c = 'data/recycle_bin.pl'
db = request.form.get('db', '').encode('utf-8')
if db != '':
c = 'data/recycle_bin_db.pl'
if os.path.exists(c):
os.remove(c)
public.writeLog('文件管理', '已关闭回收站功能!')
return public.returnJson(True, '已关闭回收站功能!')
else:
public.writeFile(c, 'True')
public.writeLog('文件管理', '已开启回收站功能!')
return public.returnJson(True, '已开启回收站功能!')
def reRecycleBinApi(self):
rPath = self.rPath
path = request.form.get('path', '').encode('utf-8')
dFile = path.replace('_mw_', '/').split('_t_')[0]
try:
import shutil
shutil.move(rPath + path, dFile)
msg = public.getInfo('移动文件[{1}]到回收站成功!', (dFile,))
public.writeLog('文件管理', msg)
return public.returnJson(True, '恢复成功!')
except Exception as e:
msg = public.getInfo('从回收站恢复[{1}]失败!', (dFile,))
public.writeLog('文件管理', msg)
return public.returnJson(False, '恢复失败!')
def delRecycleBinApi(self):
rPath = self.rPath
path = request.form.get('path', '').encode('utf-8')
empty = request.form.get('empty', '').encode('utf-8')
dFile = path.split('_t_')[0]
if not self.checkDir(path):
return public.returnJson(False, '敏感目录,请不要花样作死!')
os.system('which chattr && chattr -R -i ' + rPath + path)
if os.path.isdir(rPath + path):
import shutil
shutil.rmtree(rPath + path)
else:
os.remove(rPath + path)
tfile = path.replace('_mw_', '/').split('_t_')[0]
msg = public.getInfo('已彻底从回收站删除{1}!', (tfile,))
public.writeLog('文件管理', msg)
return public.returnJson(True, msg)
# 获取进度
def getSpeedApi(self):
data = public.getSpeed()
return public.returnJson(True, '已清空回收站!', data)
def closeRecycleBinApi(self):
rPath = self.rPath
os.system('which chattr && chattr -R -i ' + rPath)
rlist = os.listdir(rPath)
i = 0
l = len(rlist)
for name in rlist:
i += 1
path = rPath + name
public.writeSpeed(name, i, l)
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)
public.writeSpeed(None, 0, 0)
public.writeLog('文件管理', '已清空回收站!')
return public.returnJson(True, '已清空回收站!')
def deleteDirApi(self):
path = request.form.get('path', '').encode('utf-8')
if not os.path.exists(path):
return public.returnJson(False, '指定文件不存在!')
# 检查是否为.user.ini
if path.find('.user.ini'):
os.system("chattr -i '" + path + "'")
try:
if os.path.exists('data/recycle_bin.pl'):
if self.mvRecycleBin(path):
return public.returnJson(True, '已将文件移动到回收站!')
os.remove(path)
public.writeLog('文件管理', '删除文件成功!', (path,))
return public.returnJson(True, '删除文件成功!')
except:
return public.returnJson(False, '删除文件失败!')
def closeLogsApi(self):
logPath = public.getLogsDir()
os.system('rm -f ' + logPath + '/*')
os.system('kill -USR1 `cat ' + public.getServerDir() +
'openresty/nginx/logs/nginx.pid`')
public.writeLog('文件管理', '网站日志已被清空!')
tmp = self.getDirSize(logPath)
return public.returnJson(True, tmp[0].split()[0])
##### ----- end ----- ###
# 检查敏感目录
def checkDir(self, path):
path = path.replace('//', '/')
if path[-1:] == '/':
path = path[:-1]
nDirs = ('',
'/',
'/*',
'/www',
'/root',
'/boot',
'/bin',
'/etc',
'/home',
'/dev',
'/sbin',
'/var',
'/usr',
'/tmp',
'/sys',
'/proc',
'/media',
'/mnt',
'/opt',
'/lib',
'/srv',
'/selinux',
'/www/server',
'/www/server/data',
public.getRootDir())
return not path in nDirs
def getDirSize(self, path):
if public.getOs() == 'darwin':
tmp = public.execShell('du -sh ' + path)
else:
tmp = public.execShell('du -sbh ' + path)
return tmp
def checkFileName(self, filename):
# 检测文件名
nots = ['\\', '&', '*', '|', ';']
if filename.find('/') != -1:
filename = filename.split('/')[-1]
for n in nots:
if n in filename:
return False
return True
def setFileAccept(self, filename):
auth = 'www:www'
if public.getOs() == 'darwin':
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
auth = user + ':staff'
os.system('chown -R ' + auth + ' ' + filename)
os.system('chmod -R 755 ' + filename)
# 移动到回收站
def mvRecycleBin(self, path):
rPath = self.rPath
if not os.path.exists(rPath):
os.system('mkdir -p ' + rPath)
rFile = rPath + path.replace('/', '_mw_') + '_t_' + str(time.time())
try:
import shutil
shutil.move(path, rFile)
public.writeLog('TYPE_FILE', public.getInfo(
'移动文件[{1}]到回收站成功!', (path)))
return True
except:
public.writeLog('TYPE_FILE', public.getInfo(
'移动文件[{1}]到回收站失败!', (path)))
return False
def getBody(self, path):
if not os.path.exists(path):
return public.returnJson(False, '文件不存在', (path,))
if os.path.getsize(path) > 2097152:
return public.returnJson(False, u'不能在线编辑大于2MB的文件!')
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 char['encoding'] in ['GBK', 'utf-8',
'BIG5']:
data['encoding'] = 'utf-8'
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'])
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'] = u'utf-8'
return public.returnJson(True, 'OK', data)
except Exception as ex:
return public.returnJson(False, u'文件编码不被兼容,无法正确读取文件!' + str(ex))
def saveBody(self, path, data, encoding='utf-8'):
if not os.path.exists(path):
return public.returnJson(False, '文件不存在')
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)
fp.write(data)
fp.close()
public.writeLog('TYPE_FILE', '文件保存成功', (path,))
return public.returnJson(True, '文件保存成功')
except Exception as ex:
return public.returnJson(False, 'FILE_SAVE_ERR:' + str(ex))
def zip(self, sfile, dfile, stype, path):
if sfile.find(',') == -1:
if not os.path.exists(path + '/' + sfile):
return public.returnMsg(False, '指定文件不存在!')
try:
tmps = public.getRunDir() + '/tmp/panelExec.log'
if stype == 'zip':
os.system("cd '" + path + "' && zip '" + dfile +
"' -r '" + sfile + "' > " + tmps + " 2>&1")
else:
sfiles = ''
for sfile in sfile.split(','):
if not sfile:
continue
sfiles += " '" + sfile + "'"
os.system("cd '" + path + "' && tar -zcvf '" +
dfile + "' " + sfiles + " > " + tmps + " 2>&1")
self.setFileAccept(dfile)
public.writeLog("TYPE_FILE", '文件压缩成功!', (sfile, dfile))
return public.returnJson(True, '文件压缩成功!')
except:
return public.returnJson(False, '文件压缩失败!')
def delete(self, path):
if not os.path.exists(path):
return public.returnJson(False, '指定文件不存在!')
# 检查是否为.user.ini
if path.find('.user.ini') >= 0:
os.system("chattr -i '" + path + "'")
try:
if os.path.exists('data/recycle_bin.pl'):
if self.mvRecycleBin(path):
return public.returnJson(True, '已将文件移动到回收站!')
os.remove(path)
public.writeLog('TYPE_FILE', public.getInfo(
'删除文件[{1}]成功!', (path)))
return public.returnJson(True, '删除文件成功!')
except:
return public.returnJson(False, '删除文件失败!')
def getAccess(self, filename):
data = {}
try:
stat = os.stat(filename)
data['chmod'] = str(oct(stat.st_mode)[-3:])
data['chown'] = pwd.getpwuid(stat.st_uid).pw_name
except:
data['chmod'] = 755
data['chown'] = 'www'
return data
# 计算文件数量
def getCount(self, path, search):
i = 0
for name in os.listdir(path):
if search:
if name.lower().find(search) == -1:
continue
# if name[0:1] == '.':
# continue
i += 1
return i
def getDir(self, path, page=1, page_size=10, search=None):
data = {}
dirnames = []
filenames = []
info = {}
info['count'] = self.getCount(path, search)
info['row'] = page_size
info['p'] = page
info['tojs'] = 'getFiles'
pageObj = public.getPageObject(info, '1,2,3,4,5,6,7,8')
data['PAGE'] = pageObj[0]
i = 0
n = 0
for filename in os.listdir(path):
if search:
if filename.lower().find(search) == -1:
continue
i += 1
if n >= pageObj[1].ROW:
break
if i < pageObj[1].SHIFT:
continue
try:
filePath = (path + '/' + filename).encode('utf8')
link = ''
if os.path.islink(filePath):
filePath = os.readlink(filePath)
link = ' -> ' + filePath
if not os.path.exists(filePath):
filePath = path + '/' + filePath
if not os.path.exists(filePath):
continue
stat = os.stat(filePath)
accept = str(oct(stat.st_mode)[-3:])
mtime = str(int(stat.st_mtime))
user = ''
try:
user = pwd.getpwuid(stat.st_uid).pw_name
except:
user = str(stat.st_uid)
size = str(stat.st_size)
if os.path.isdir(filePath):
dirnames.append(filename + ';' + size + ';' +
mtime + ';' + accept + ';' + user + ';' + link)
else:
filenames.append(filename + ';' + size + ';' +
mtime + ';' + accept + ';' + user + ';' + link)
n += 1
except:
continue
data['DIR'] = sorted(dirnames)
data['FILES'] = sorted(filenames)
data['PATH'] = path.replace('//', '/')
return public.getJson(data)
+404
View File
@@ -0,0 +1,404 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
from flask import request
class firewall_api:
__isFirewalld = False
__isUfw = False
__isMac = False
def __init__(self):
if os.path.exists('/usr/sbin/firewalld'):
self.__isFirewalld = True
if os.path.exists('/usr/sbin/ufw'):
self.__isUfw = True
if public.isAppleSystem():
self.__isMac = True
##### ----- start ----- ###
# 添加屏蔽IP
def addDropAddressApi(self):
import re
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
rep = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
if not re.search(rep, port):
return public.returnJson(False, '您输入的IP地址不合法!')
address = port
if public.M('firewall').where("port=?", (address,)).count() > 0:
return public.returnJson(False, '您要放屏蔽的IP已存在屏蔽列表,无需重复处理!')
if self.__isUfw:
public.execShell('ufw deny from ' + address + ' to any')
else:
if self.__isFirewalld:
cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \
address + '" drop\''
public.execShell(cmd)
else:
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
public.execShell(cmd)
msg = public.getInfo('屏蔽IP[{1}]成功!', (address,))
public.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall').add('port,ps,addtime', (address, ps, addtime))
self.firewallReload()
return public.returnJson(True, '添加成功!')
# 添加放行端口
def addAcceptPortApi(self):
import re
import time
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
stype = request.form.get('type', '').strip()
rep = "^\d{1,5}(:\d{1,5})?$"
if not re.search(rep, port):
return public.returnJson(False, '端口范围不正确!')
if public.M('firewall').where("port=?", (port,)).count() > 0:
return public.returnJson(False, '您要放行的端口已存在,无需重复放行!')
msg = public.getInfo('放行端口[{1}]成功', (port,))
public.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
public.M('firewall').add('port,ps,addtime', (port, ps, addtime))
self.addAcceptPort(port)
self.firewallReload()
return public.returnJson(True, '添加放行(' + port + ')端口成功!')
# 删除IP屏蔽
def delDropAddressApi(self):
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
sid = request.form.get('id', '').strip()
address = port
if self.__isUfw:
public.execShell('ufw delete deny from ' + address + ' to any')
else:
if self.__isFirewalld:
public.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
elif self.__isMac:
pass
else:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
public.execShell(cmd)
msg = public.getInfo('解除IP[{1}]的屏蔽!', (address,))
public.writeLog("防火墙管理", msg)
public.M('firewall').where("id=?", (sid,)).delete()
self.firewallReload()
return public.returnJson(True, '删除成功!')
# 删除放行端口
def delAcceptPortApi(self):
port = request.form.get('port', '').strip()
sid = request.form.get('id', '').strip()
mw_port = public.readFile('data/port.pl')
try:
if(port == mw_port):
return public.returnJson(False, '失败,不能删除当前面板端口!')
if self.__isUfw:
public.execShell('ufw delete allow ' + port + '/tcp')
else:
if self.__isFirewalld:
public.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
public.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
else:
public.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
msg = public.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
public.writeLog("防火墙管理", msg)
public.M('firewall').where("id=?", (sid,)).delete()
self.firewallReload()
return public.returnJson(True, '删除成功!')
except Exception as e:
return public.returnJson(False, '删除失败!:' + str(e))
def getWwwPathApi(self):
path = public.getLogsDir()
return public.getJson({'path': path})
def getListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
return self.getList(int(p), int(limit))
def getLogListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
return self.getLogList(int(p), int(limit), search)
def getSshInfoApi(self):
file = '/etc/ssh/sshd_config'
conf = public.readFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
port = re.search(rep, conf).groups(0)[0]
isPing = True
try:
if public.isAppleSystem():
isPing = True
else:
file = '/etc/sysctl.conf'
conf = public.readFile(file)
rep = "#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)"
tmp = re.search(rep, conf).groups(0)[0]
if tmp == '1':
isPing = False
except:
isPing = True
import system_api
panelsys = system_api.system_api()
version = panelsys.getSystemVersion()
if os.path.exists('/usr/bin/apt-get'):
if os.path.exists('/etc/init.d/sshd'):
cmd = "service sshd status | grep -P '(dead|stop)'|grep -v grep"
status = public.execShell(cmd)
else:
cmd = "service ssh status | grep -P '(dead|stop)'|grep -v grep"
status = public.execShell(cmd)
else:
if version.find(' 7.') != -1:
cmd = "systemctl status sshd.service | grep 'dead'|grep -v grep"
status = public.execShell(cmd)
else:
cmd = "/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep"
status = public.execShell(cmd)
if len(status[0]) > 3:
status = False
else:
status = True
data = {}
data['port'] = port
data['status'] = status
data['ping'] = isPing
if public.isAppleSystem():
data['firewall_status'] = False
else:
data['firewall_status'] = self.getFwStatus()
return public.getJson(data)
def setSshPortApi(self):
port = request.form.get('port', '1').strip()
if int(port) < 22 or int(port) > 65535:
return public.returnJson(False, '端口范围必需在22-65535之间!')
ports = ['21', '25', '80', '443', '7200', '8080', '888', '8888']
if port in ports:
return public.returnJson(False, '(' + port + ')' + '特殊端口不可设置!')
file = '/etc/ssh/sshd_config'
conf = public.readFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
conf = re.sub(rep, "Port " + port + "\n", conf)
public.writeFile(file, conf)
if self.__isFirewalld:
public.execShell('setenforce 0')
public.execShell(
'sed -i "s#SELINUX=enforcing#SELINUX=disabled#" /etc/selinux/config')
public.execShell("systemctl restart sshd.service")
elif self.__isUfw:
public.execShell('ufw allow ' + port + '/tcp')
public.execShell("service ssh restart")
else:
public.execShell(
'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
public.execShell("/etc/init.d/sshd restart")
self.firewallReload()
# public.M('firewall').where(
# "ps=?", ('SSH远程管理服务',)).setField('port', port)
msg = public.getInfo('改SSH端口为[{1}]成功!', port)
public.writeLog("防火墙管理", msg)
return public.returnJson(True, '修改成功!')
def setSshStatusApi(self):
if public.isAppleSystem():
return public.returnJson(True, '开发机不能操作!')
status = request.form.get('status', '1').strip()
version = public.readFile('/etc/redhat-release')
if int(status) == 1:
msg = 'SSH服务已停用'
act = 'stop'
else:
msg = 'SSH服务已启用'
act = 'start'
if not os.path.exists('/etc/redhat-release'):
public.execShell('service ssh ' + act)
elif version.find(' 7.') != -1:
public.execShell("systemctl " + act + " sshd.service")
else:
public.execShell("/etc/init.d/sshd " + act)
public.writeLog("防火墙管理", msg)
return public.returnJson(True, '操作成功!')
def setPingApi(self):
if public.isAppleSystem():
return public.returnJson(True, '开发机不能操作!')
status = request.form.get('status')
filename = '/etc/sysctl.conf'
conf = public.readFile(filename)
if conf.find('net.ipv4.icmp_echo') != -1:
rep = u"net\.ipv4\.icmp_echo.*"
conf = re.sub(rep, 'net.ipv4.icmp_echo_ignore_all=' + status, conf)
else:
conf += "\nnet.ipv4.icmp_echo_ignore_all=" + status
public.writeFile(filename, conf)
public.execShell('sysctl -p')
return public.returnJson(True, '设置成功!')
def setFwApi(self):
if public.isAppleSystem():
return public.returnJson(True, '开发机不能设置!')
status = request.form.get('status', '1')
if status == '1':
if self.__isUfw:
public.execShell('/usr/sbin/ufw stop')
return
if self.__isFirewalld:
public.execShell('systemctl stop firewalld.service')
elif self.__isMac:
pass
else:
public.execShell('/etc/init.d/iptables save')
public.execShell('/etc/init.d/iptables stop')
else:
if self.__isUfw:
public.execShell('/usr/sbin/ufw start')
return
if self.__isFirewalld:
public.execShell('systemctl start firewalld.service')
elif self.__isMac:
pass
else:
public.execShell('/etc/init.d/iptables save')
public.execShell('/etc/init.d/iptables restart')
return public.returnJson(True, '设置成功!')
def delPanelLogsApi(self):
public.M('logs').where('id>?', (0,)).delete()
public.writeLog('面板设置', '面板操作日志已清空!')
return public.returnJson(True, '面板操作日志已清空!')
##### ----- start ----- ###
def getList(self, page, limit):
start = (page - 1) * limit
_list = public.M('firewall').field('id,port,ps,addtime').limit(
str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = public.M('firewall').count()
_page = {}
_page['count'] = count
_page['tojs'] = 'showAccept'
_page['p'] = page
data['page'] = public.getPage(_page)
return public.getJson(data)
def getLogList(self, page, limit, search=''):
find_search = ''
if search != '':
find_search = "type like '%" + search + "%' or log like '%" + \
search + "%' or addtime like '%" + search + "%'"
start = (page - 1) * limit
_list = public.M('logs').where(find_search, ()).field(
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = public.M('logs').where(find_search, ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getLogs'
_page['p'] = page
data['page'] = public.getPage(_page)
return public.getJson(data)
def addAcceptPort(self, port):
if self.__isUfw:
public.execShell('ufw allow ' + port + '/tcp')
else:
if self.__isFirewalld:
port = port.replace(':', '-')
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
public.execShell(cmd)
elif self.__isMac:
pass
else:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
public.execShell(cmd)
def firewallReload(self):
if self.__isUfw:
public.execShell('/usr/sbin/ufw reload')
return
if self.__isFirewalld:
public.execShell('firewall-cmd --reload')
elif self.__isMac:
pass
else:
public.execShell('/etc/init.d/iptables save')
public.execShell('/etc/init.d/iptables restart')
def getFwStatus(self):
if self.__isUfw:
cmd = "ps -ef|grep ufw |grep -v grep | awk '{print $2}'"
data = public.execShell(cmd)
if data[0] == '':
return False
return True
if self.__isFirewalld:
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
data = public.execShell(cmd)
if data[0] == '':
return False
return True
elif self.__isMac:
return False
else:
cmd = "ps -ef|grep iptables |grep -v grep | awk '{print $2}'"
data = public.execShell(cmd)
if data[0] == '':
return False
return True
+2 -2
View File
@@ -29,8 +29,8 @@ class Page():
__END_NUM = None # 结束行
def __init__(self):
tmp = public.getMsg('PAGE')
if tmp:
# tmp = public.getMsg('PAGE')
if False:
self.__PREV = tmp['PREV']
self.__NEXT = tmp['NEXT']
self.__START = tmp['START']
-291
View File
@@ -1,291 +0,0 @@
# coding: utf-8
import psutil
import time
import os
import public
import re
import json
class plugin_api:
__tasks = None
__plugin_dir = 'plugins'
__type = 'data/json/type.json'
__index = 'data/json/index.json'
setupPath = None
def __init__(self):
self.setupPath = 'server'
# self.__plugin_dir = public.getRunDir() + '/plugins'
# 进程是否存在
def processExists(self, pname, exe=None):
try:
if not self.pids:
self.pids = psutil.pids()
for pid in self.pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe:
return True
else:
if p.exe() == exe:
return True
except:
pass
return False
except:
return True
# 检查是否正在安装
def checkSetupTask(self, sName):
if not self.__tasks:
self.__tasks = public.M('tasks').where(
"status!=?", ('1',)).field('status,name').select()
if sName.find('php-') != -1:
tmp = sName.split('-')
sName = tmp[0]
version = tmp[1]
isTask = '1'
for task in self.__tasks:
tmpt = public.getStrBetween('[', ']', task['name'])
if not tmpt:
continue
tmp1 = tmpt.split('-')
name1 = tmp1[0].lower()
if sName == 'php':
if name1 == sName and tmp1[1] == version:
isTask = task['status']
else:
if name1 == 'pure':
name1 = 'pure-ftpd'
if name1 == sName:
isTask = task['status']
return isTask
def checkStatus(self, info):
pass
def checkDisplayIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
if type(version) == list:
for index in range(len(version)):
vname = name + '-' + version[index]
if vname in indexList:
return True
else:
vname = name + '-' + version
if vname in indexList:
return True
return False
def getVersion(self, path):
version_f = path + '/version.pl'
if os.path.exists(version_f):
return public.readFile(version_f).strip()
return ''
# 构造本地插件信息
def getPluginInfo(self, info):
checks = ''
path = ''
coexist = False
if info["checks"][0:1] == '/':
checks = info["checks"]
else:
checks = public.getRootDir() + '/' + info['checks']
if info.has_key('path'):
path = info['path']
if path[0:1] != '/':
path = public.getRootDir() + '/' + path
if info.has_key('coexist') and info['coexist']:
coexist = True
pluginInfo = {
"id": 10000,
"pid": info['pid'],
"type": 1000,
"name": info['name'],
"title": info['title'],
"ps": info['ps'],
"dependnet": "",
"mutex": "",
"path": path,
"install_checks": checks,
"uninsatll_checks": checks,
"coexist": coexist,
"versions": info['versions'],
# "updates": info['updates'],
"display": False,
"setup": False,
"setup_version": "",
"status": False,
}
pluginInfo['task'] = self.checkSetupTask(pluginInfo['name'])
if checks.find('VERSION') > -1:
pluginInfo['install_checks'] = checks.replace(
'VERSION', info['versions'])
if path.find('VERSION') > -1:
pluginInfo['path'] = path.replace(
'VERSION', info['versions'])
pluginInfo['display'] = self.checkDisplayIndex(
info['name'], pluginInfo['versions'])
pluginInfo['setup'] = os.path.exists(pluginInfo['install_checks'])
if coexist and pluginInfo['setup']:
pluginInfo['setup_version'] = info['versions']
else:
pluginInfo['setup_version'] = self.getVersion(
pluginInfo['path'])
# pluginInfo['status'] = os.path.exists(pluginInfo['install_checks'])
return pluginInfo
def makeCoexist(self, data):
plugins_info = []
for index in range(len(data['versions'])):
tmp = data.copy()
tmp['title'] = tmp['title'] + \
'-' + data['versions'][index]
tmp['versions'] = data['versions'][index]
pg = self.getPluginInfo(tmp)
plugins_info.append(pg)
return plugins_info
def makeList(self, data, sType='0'):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
def getAllList(self, sType='0'):
ret = {}
ret['type'] = json.loads(public.readFile(self.__type))
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception, e:
print e
return plugins_info
def getPluginList(self, sType, sPage=1, sPageSize=15):
ret = {}
ret['type'] = json.loads(public.readFile(self.__type))
plugins_info = self.getAllList(sType)
args = {}
args['count'] = len(plugins_info)
args['p1'] = sPage
ret['data'] = plugins_info
ret['list'] = public.getPage(args)
return ret
def getIndexList(self):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
plist = []
app = []
for i in indexList:
info = i.split('-')
if not info[0] in app:
app.append(info[0])
path = self.__plugin_dir + '/' + info[0]
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data)
for index in range(len(tmp_data)):
if tmp_data[index]['versions'] == info[1] or info[1] in tmp_data[index]['versions']:
tmp_data[index]['display'] = True
plist.append(tmp_data[index])
continue
except Exception, e:
print e
return plist
def setIndexSort(self, sort):
data = sort.split('|')
public.writeFile(self.__index, json.dumps(data))
return True
def addIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if vname in indexList:
return public.returnJson(False, '请不要重复添加!')
if len(indexList) >= 12:
return public.returnJson(False, '首页最多只能显示12个软件!')
indexList.append(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '添加成功!')
def removeIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if not vname in indexList:
return public.returnJson(True, '删除成功!')
indexList.remove(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '删除成功!')
def run(self):
pass
+759
View File
@@ -0,0 +1,759 @@
# coding: utf-8
import psutil
import time
import os
import public
import re
import json
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import threading
import multiprocessing
from flask import request
class pa_thread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name = name
self.func = func
self.args = args
self.result = self.func(*self.args)
def getResult(self):
try:
return self.result
except Exception:
return None
class plugins_api:
__tasks = None
__plugin_dir = 'plugins'
__type = 'data/json/type.json'
__index = 'data/json/index.json'
setupPath = None
def __init__(self):
self.setupPath = 'server'
##### ----- start ----- ###
def listApi(self):
sType = request.args.get('type', '0')
sPage = request.args.get('p', '1')
# print sPage
data = self.getPluginList(sType, int(sPage))
return public.getJson(data)
def fileApi(self):
name = request.args.get('name', '')
if name.strip() == '':
return ''
f = request.args.get('f', '')
if f.strip() == '':
return ''
file = self.__plugin_dir + '/' + name + '/' + f
if not os.path.exists(file):
return ''
c = public.readFile(file)
return c
def indexListApi(self):
data = self.getIndexList()
return public.getJson(data)
def indexSortApi(self):
sort = request.form.get('ssort', '')
if sort.strip() == '':
return public.returnJson(False, '排序数据不能为空!')
data = self.setIndexSort(sort)
if data:
return public.returnJson(True, '成功!')
return public.returnJson(False, '失败!')
def installApi(self):
rundir = public.getRunDir()
name = request.form.get('name', '')
version = request.form.get('version', '')
mmsg = '安装'
if hasattr(request.form, 'upgrade'):
mtype = 'update'
mmsg = 'upgrade'
if name.strip() == '':
return public.returnJson(False, '缺少插件名称!', ())
if version.strip() == '':
return public.returnJson(False, '缺少版本信息!', ())
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
print infoJsonPos
if not os.path.exists(infoJsonPos):
return public.retJson(False, '配置文件不存在!', ())
pluginInfo = json.loads(public.readFile(infoJsonPos))
execstr = "cd " + os.getcwd() + "/plugins/" + \
name + " && /bin/bash " + pluginInfo["shell"] \
+ " install " + version
taskAdd = (None, mmsg + '[' + name + '-' + version + ']',
'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
public.M('tasks').add('id,name,type,status,addtime, execstr', taskAdd)
return public.returnJson(True, '已将安装任务添加到队列!')
def uninstallApi(self):
rundir = public.getRunDir()
name = request.form.get('name', '')
version = request.form.get('version', '')
if name.strip() == '':
return public.returnJson(False, "缺少插件名称!", ())
if version.strip() == '':
return public.returnJson(False, "缺少版本信息!", ())
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
if not os.path.exists(infoJsonPos):
return public.retJson(False, "配置文件不存在!", ())
pluginInfo = json.loads(public.readFile(infoJsonPos))
execstr = "cd " + os.getcwd() + "/plugins/" + \
name + " && /bin/bash " + pluginInfo["shell"] \
+ " uninstall " + version
taskAdd = (None, '卸载[' + name + '-' + version + ']',
'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
public.M('tasks').add('id,name,type,status,addtime, execstr', taskAdd)
return public.returnJson(True, '已将卸载任务添加到队列!')
def checkApi(self):
name = request.form.get('name', '')
if name.strip() == '':
return public.returnJson(False, "缺少插件名称!", ())
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
if not os.path.exists(infoJsonPos):
return public.returnJson(False, "配置文件不存在!", ())
return public.returnJson(True, "插件存在!", ())
def setIndexApi(self):
name = request.form.get('name', '')
status = request.form.get('status', '0')
version = request.form.get('version', '')
if status == '1':
return self.addIndex(name, version)
return self.removeIndex(name, version)
def settingApi(self):
name = request.args.get('name', '')
html = self.__plugin_dir + '/' + name + '/index.html'
return public.readFile(html)
def runApi(self):
name = request.form.get('name', '')
func = request.form.get('func', '')
version = request.form.get('version', '')
args = request.form.get('args', '')
script = request.form.get('script', 'index')
data = self.run(name, func, version, args, script)
if data[1] == '':
return public.returnJson(True, "OK", data[0].strip())
return public.returnJson(False, data[1].strip())
def updateZipApi(self):
tmp_path = public.getRootDir() + '/temp'
if not os.path.exists(tmp_path):
os.makedirs(tmp_path)
public.execShell("rm -rf " + tmp_path + '/*')
tmp_file = tmp_path + '/plugin_tmp.zip'
from werkzeug.utils import secure_filename
from flask import request
f = request.files['plugin_zip']
if f.filename[-4:] != '.zip':
return public.returnJson(False, '仅支持zip文件!')
f.save(tmp_file)
public.execShell('cd ' + tmp_path + ' && unzip ' + tmp_file)
os.remove(tmp_file)
p_info = tmp_path + '/info.json'
if not os.path.exists(p_info):
d_path = None
for df in os.walk(tmp_path):
if len(df[2]) < 3:
continue
if not 'info.json' in df[2]:
continue
if not 'install.sh' in df[2]:
continue
if not os.path.exists(df[0] + '/info.json'):
continue
d_path = df[0]
if d_path:
tmp_path = d_path
p_info = tmp_path + '/info.json'
try:
data = json.loads(public.readFile(p_info))
data['size'] = public.getPathSize(tmp_path)
if not 'author' in data:
data['author'] = '未知'
if not 'home' in data:
data['home'] = 'https://www.bt.cn/bbs/forum-40-1.html'
plugin_path = public.getPluginDir() + data['name'] + '/info.json'
data['old_version'] = '0'
data['tmp_path'] = tmp_path
if os.path.exists(plugin_path):
try:
old_info = json.loads(public.ReadFile(plugin_path))
data['old_version'] = old_info['versions']
except:
pass
except:
public.execShell("rm -rf " + tmp_path)
return public.returnJson(False, '在压缩包中没有找到插件信息,请检查插件包!')
return public.getJson(data)
def inputZipApi(self):
plugin_name = request.form.get('plugin_name', '')
tmp_path = request.form.get('tmp_path', '')
if not os.path.exists(tmp_path):
return public.returnJson(False, '临时文件不存在,请重新上传!')
plugin_path = public.getPluginDir() + '/' + plugin_name
if not os.path.exists(plugin_path):
print public.execShell('mkdir -p ' + plugin_path)
public.execShell("\cp -rf " + tmp_path + '/* ' + plugin_path + '/')
public.execShell('chmod -R 755 ' + plugin_path)
p_info = public.readFile(plugin_path + '/info.json')
if p_info:
public.writeLog('软件管理', '安装第三方插件[%s]' %
json.loads(p_info)['title'])
return public.returnJson(True, '安装成功!')
public.execShell("rm -rf " + plugin_path)
return public.returnJson(False, '安装失败!')
##### ----- end ----- ###
# 进程是否存在
def processExists(self, pname, exe=None):
try:
if not self.pids:
self.pids = psutil.pids()
for pid in self.pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe:
return True
else:
if p.exe() == exe:
return True
except:
pass
return False
except:
return True
# 检查是否正在安装
def checkSetupTask(self, sName):
sName = ''
version = ''
if not self.__tasks:
self.__tasks = public.M('tasks').where(
"status!=?", ('1',)).field('status,name').select()
if sName.find('php-') != -1:
tmp = sName.split('-')
sName = tmp[0]
version = tmp[1]
isTask = '1'
for task in self.__tasks:
tmpt = public.getStrBetween('[', ']', task['name'])
if not tmpt:
continue
tmp1 = tmpt.split('-')
name1 = tmp1[0].lower()
if sName == 'php':
if name1 == sName and tmp1[1] == version:
isTask = task['status']
else:
if name1 == 'pure':
name1 = 'pure-ftpd'
if name1 == sName:
isTask = task['status']
return isTask
def checkStatus(self, info):
if not info['setup']:
return False
data = self.run(info['name'], 'status', info['setup_version'])
if data[0] == 'start':
return True
return False
def checkStatusProcess(self, info, i, return_dict):
if not info['setup']:
return_dict[i] = False
return
data = self.run(info['name'], 'status', info['setup_version'])
if data[0] == 'start':
return_dict[i] = True
else:
return_dict[i] = False
def checkStatusThreads(self, info, i):
if not info['setup']:
return False
data = self.run(info['name'], 'status', info['setup_version'])
if data[0] == 'start':
return True
else:
return False
def checkStatusMThreads(self, plugins_info):
try:
threads = []
ntmp_list = range(len(plugins_info))
for i in ntmp_list:
t = pa_thread(self.checkStatusThreads, (plugins_info[i], i))
threads.append(t)
for i in ntmp_list:
threads[i].start()
for i in ntmp_list:
threads[i].join()
for i in ntmp_list:
t = threads[i].getResult()
plugins_info[i]['status'] = t
except Exception as e:
print 'checkStatusMThreads:', str(e)
return plugins_info
def checkStatusMProcess(self, plugins_info):
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
for i in range(len(plugins_info)):
p = multiprocessing.Process(
target=self.checkStatusProcess, args=(plugins_info[i], i, return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
returnData = return_dict.values()
for i in ntmp_list:
plugins_info[i]['status'] = returnData[i]
return plugins_info
def checkDisplayIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
if type(version) == list:
for index in range(len(version)):
vname = name + '-' + version[index]
if vname in indexList:
return True
else:
vname = name + '-' + version
if vname in indexList:
return True
return False
def getVersion(self, path):
version_f = path + '/version.pl'
if os.path.exists(version_f):
return public.readFile(version_f).strip()
return ''
# 构造本地插件信息
def getPluginInfo(self, info):
checks = ''
path = ''
coexist = False
if info["checks"][0:1] == '/':
checks = info["checks"]
else:
checks = public.getRootDir() + '/' + info['checks']
if info.has_key('path'):
path = info['path']
if path[0:1] != '/':
path = public.getRootDir() + '/' + path
if info.has_key('coexist') and info['coexist']:
coexist = True
pluginInfo = {
"id": 10000,
"pid": info['pid'],
"type": 1000,
"name": info['name'],
"title": info['title'],
"ps": info['ps'],
"dependnet": "",
"mutex": "",
"path": path,
"install_checks": checks,
"uninsatll_checks": checks,
"coexist": coexist,
"versions": info['versions'],
# "updates": info['updates'],
"display": False,
"setup": False,
"setup_version": "",
"status": False,
}
pluginInfo['task'] = self.checkSetupTask(pluginInfo['name'])
if checks.find('VERSION') > -1:
pluginInfo['install_checks'] = checks.replace(
'VERSION', info['versions'])
if path.find('VERSION') > -1:
pluginInfo['path'] = path.replace(
'VERSION', info['versions'])
pluginInfo['display'] = self.checkDisplayIndex(
info['name'], pluginInfo['versions'])
pluginInfo['setup'] = os.path.exists(pluginInfo['install_checks'])
if coexist and pluginInfo['setup']:
pluginInfo['setup_version'] = info['versions']
else:
pluginInfo['setup_version'] = self.getVersion(
pluginInfo['install_checks'])
# pluginInfo['status'] = self.checkStatus(pluginInfo)
pluginInfo['status'] = False
return pluginInfo
def makeCoexist(self, data):
plugins_info = []
for index in range(len(data['versions'])):
tmp = data.copy()
tmp['title'] = tmp['title'] + \
'-' + data['versions'][index]
tmp['versions'] = data['versions'][index]
pg = self.getPluginInfo(tmp)
plugins_info.append(pg)
return plugins_info
def makeList(self, data, sType='0'):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
def getAllList(self, sType='0'):
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception, e:
print e
return plugins_info
def getAllListPage(self, sType='0', page=1, pageSize=10):
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception, e:
print e
start = (page - 1) * pageSize
end = start + pageSize
_plugins_info = plugins_info[start:end]
_plugins_info = self.checkStatusMThreads(_plugins_info)
return (_plugins_info, len(plugins_info))
def makeListThread(self, data, sType='0'):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
def getAllListThread(self, sType='0'):
plugins_info = []
tmp_list = []
threads = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
data = json.loads(public.readFile(json_file))
if sType == '0':
tmp_list.append(data)
if (data['pid'] == sType):
tmp_list.append(data)
ntmp_list = range(len(tmp_list))
for i in ntmp_list:
t = pa_thread(self.makeListThread, (tmp_list[i], sType))
threads.append(t)
for i in ntmp_list:
threads[i].start()
for i in ntmp_list:
threads[i].join()
for i in ntmp_list:
t = threads[i].getResult()
for index in range(len(t)):
plugins_info.append(t[index])
return plugins_info
def makeListProcess(self, data, sType, i, return_dict):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return_dict[i] = plugins_info
# return plugins_info
def getAllListProcess(self, sType='0'):
plugins_info = []
tmp_list = []
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
data = json.loads(public.readFile(json_file))
if sType == '0':
tmp_list.append(data)
if (data['pid'] == sType):
tmp_list.append(data)
ntmp_list = range(len(tmp_list))
for i in ntmp_list:
p = multiprocessing.Process(
target=self.makeListProcess, args=(tmp_list[i], sType, i, return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
returnData = return_dict.values()
for i in ntmp_list:
for index in range(len(returnData[i])):
plugins_info.append(returnData[i][index])
return plugins_info
def getPluginList(self, sType, sPage=1, sPageSize=10):
# print sType, sPage, sPageSize
ret = {}
ret['type'] = json.loads(public.readFile(self.__type))
# plugins_info = self.getAllListThread(sType)
# plugins_info = self.getAllListProcess(sType)
data = self.getAllListPage(sType, sPage, sPageSize)
ret['data'] = data[0]
args = {}
args['count'] = data[1]
args['p'] = sPage
args['tojs'] = 'getSList'
args['row'] = sPageSize
ret['list'] = public.getPage(args)
return ret
def getIndexList(self):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
plist = []
app = []
for i in indexList:
info = i.split('-')
if not info[0] in app:
app.append(info[0])
path = self.__plugin_dir + '/' + info[0]
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data)
for index in range(len(tmp_data)):
if tmp_data[index]['versions'] == info[1] or info[1] in tmp_data[index]['versions']:
tmp_data[index]['display'] = True
plist.append(tmp_data[index])
continue
except Exception, e:
print 'getIndexList:', e
# 使用gevent模式时,无法使用多进程
# plist = self.checkStatusMProcess(plist)
plist = self.checkStatusMThreads(plist)
return plist
def setIndexSort(self, sort):
data = sort.split('|')
public.writeFile(self.__index, json.dumps(data))
return True
def addIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if vname in indexList:
return public.returnJson(False, '请不要重复添加!')
if len(indexList) >= 12:
return public.returnJson(False, '首页最多只能显示12个软件!')
indexList.append(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '添加成功!')
def removeIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if not vname in indexList:
return public.returnJson(True, '删除成功!')
indexList.remove(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '删除成功!')
def run(self, name, func, version, args='', script='index'):
path = public.getRunDir() + '/' + self.__plugin_dir + \
'/' + name + '/' + script + '.py'
py = 'python ' + path
if args == '':
py_cmd = py + ' ' + func + ' ' + version
else:
py_cmd = py + ' ' + func + ' ' + version + ' ' + args
if not os.path.exists(path):
return ('', '')
data = public.execShell(py_cmd)
# data = os.popen(py_cmd).read()
if public.isAppleSystem():
print py_cmd
# print os.path.exists(py_cmd)
return (data[0].strip(), data[1].strip())
+362 -188
View File
@@ -46,9 +46,83 @@ def getRootDir():
return os.path.dirname(os.path.dirname(getRunDir()))
def getPluginDir():
return getRunDir() + '/plugins'
def getServerDir():
return getRootDir() + '/server'
def getWwwDir():
file = getRunDir() + '/data/site.pl'
if os.path.exists(file):
return readFile(file).strip()
return getRootDir() + '/wwwroot'
def setWwwDir(wdir):
file = getRunDir() + '/data/site.pl'
return writeFile(file, wdir)
def getLogsDir():
return getRootDir() + '/wwwlogs'
def getBackupDir():
return getRootDir() + '/backup'
def setBackupDir(bdir):
file = getRunDir() + '/data/backup.pl'
return writeFile(file, bdir)
def getOs():
os = execShell('uname')
return os[0].lower().strip()
return sys.platform
def isAppleSystem():
if getOs() == 'darwin':
return True
return False
def deleteFile(file):
if os.path.exists(file):
os.remove(file)
def isInstalledWeb():
path = getServerDir() + '/openresty/nginx/sbin/nginx'
if os.path.exists(path):
return True
return False
def restartWeb():
if isInstalledWeb():
initd = getServerDir() + '/openresty/init.d/openresty'
execShell(initd + ' ' + 'reload')
def restartMw():
import system_api
system_api.system_api().restartMw()
def checkWebConfig():
op_dir = getServerDir() + '/openresty'
cmd = "ulimit -n 10240 && " + op_dir + \
"/nginx/sbin/nginx -t -c " + op_dir + "/nginx/conf/nginx.conf"
result = execShell(cmd)
searchStr = 'successful'
if result[1].find(searchStr) == -1:
msg = getInfo('配置文件错误: {1}', (result[1],))
writeLog("软件管理", msg)
return result[1]
return True
def M(table):
@@ -57,6 +131,11 @@ def M(table):
def getPage(args, result='1,2,3,4,5,8'):
data = getPageObject(args, result)
return data[0]
def getPageObject(args, result='1,2,3,4,5,8'):
# 取分页
import page
# 实例化分页类
@@ -69,7 +148,7 @@ def getPage(args, result='1,2,3,4,5,8'):
info['row'] = 10
if args.has_key('row'):
info['row'] = args['row']
info['row'] = int(args['row'])
info['p'] = 1
if args.has_key('p'):
@@ -79,7 +158,7 @@ def getPage(args, result='1,2,3,4,5,8'):
if args.has_key('tojs'):
info['return_js'] = args['tojs']
return page.GetPage(info, result)
return (page.GetPage(info, result), page)
def md5(str):
@@ -124,15 +203,23 @@ def getJson(data):
return json.dumps(data)
def returnJson(status, msg, args=()):
# 取通用Json返回
return getJson(returnMsg(status, msg, args))
def returnData(status, msg, data=None):
return {'status': status, 'msg': msg, 'data': data}
def returnJson(status, msg, data=None):
# if data == None:
# return {'status': status, 'msg': msg}
# return {'status': status, 'msg': msg, 'data': data}
if data == None:
return getJson({'status': status, 'msg': msg})
return getJson({'status': status, 'msg': msg, 'data': data})
def returnMsg(status, msg, args=()):
# 取通用字曲返回
logMessage = json.loads(
readFile('static/language/' + getLanguage() + '/public.json'))
pjson = 'static/language/' + getLanguage() + '/public.json'
logMessage = json.loads(readFile(pjson))
keys = logMessage.keys()
if msg in keys:
@@ -209,22 +296,12 @@ def writeLog(type, logMsg, args=()):
import time
import db
import json
logMessage = json.loads(
readFile('static/language/' + getLanguage() + '/log.json'))
keys = logMessage.keys()
if logMsg in keys:
logMsg = logMessage[logMsg]
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
logMsg = logMsg.replace(rep, args[i])
if type in keys:
type = logMessage[type]
sql = db.Sql()
mDate = time.strftime('%Y-%m-%d %X', time.localtime())
data = (type, logMsg, mDate)
result = sql.table('logs').add('type,log,addtime', data)
except:
pass
except Exception as e:
print e
def writeFile(filename, str):
@@ -238,39 +315,100 @@ def writeFile(filename, str):
return False
def httpGet(url, timeout=30):
# 发送GET请求
try:
import urllib2
import ssl
def HttpGet(url, timeout=10):
"""
发送GET请求
@url 被请求的URL地址(必需)
@timeout 超时时间默认60秒
return string
"""
if sys.version_info[0] == 2:
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
response = urllib2.urlopen(url, timeout=timeout)
return response.read()
except Exception, ex:
# WriteLog('网络诊断',str(ex) + '['+url+']');
return str(ex)
import urllib2
import ssl
if sys.version_info[0] == 2:
reload(urllib2)
reload(ssl)
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
response = urllib2.urlopen(url, timeout=timeout)
return response.read()
except Exception as ex:
return str(ex)
else:
try:
import urllib.request
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
response = urllib.request.urlopen(url, timeout=timeout)
result = response.read()
if type(result) == bytes:
result = result.decode('utf-8')
return result
except Exception as ex:
return str(ex)
def httpPost(url, data, timeout=30):
# 发送POST请求
try:
import urllib
import urllib2
import ssl
def HttpGet2(url, timeout):
import urllib
import urllib2
req = urllib2.Request(url)
res = urllib2.urlopen(req, timeout=timeout)
result = res.read()
return result
def httpGet(url, timeout=10):
return HttpGet2(url, timeout)
def HttpPost(url, data, timeout=10):
"""
发送POST请求
@url 被请求的URL地址(必需)
@data POST参数,可以是字符串或字典(必需)
@timeout 超时时间默认60秒
return string
"""
if sys.version_info[0] == 2:
try:
import urllib
import urllib2
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
data = urllib.urlencode(data)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req, timeout=timeout)
return response.read()
except Exception, ex:
# WriteLog('网络诊断',str(ex) + '['+url+']');
return str(ex)
data = urllib.urlencode(data)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req, timeout=timeout)
return response.read()
except Exception as ex:
return str(ex)
else:
try:
import urllib.request
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req, timeout=timeout)
result = response.read()
if type(result) == bytes:
result = result.decode('utf-8')
return result
except Exception as ex:
return str(ex)
def httpPost(url, data, timeout=10):
return HttpPost(url, data, timeout)
def writeSpeed(title, used, total, speed=0):
@@ -288,11 +426,12 @@ def writeSpeed(title, used, total, speed=0):
def getSpeed():
# 取进度
data = readFile('/tmp/panelSpeed.pl')
path = public.getRootDir()
data = readFile(path + '/tmp/panelSpeed.pl')
if not data:
data = json.dumps({'title': None, 'progress': 0,
'total': 0, 'used': 0, 'speed': 0})
writeFile('/tmp/panelSpeed.pl', data)
writeFile(path + '/tmp/panelSpeed.pl', data)
return json.loads(data)
@@ -327,25 +466,57 @@ def getLastLine(inputfile, lineNum):
return getMsg('TASK_SLEEP')
def serviceReload():
# 重载Web服务配置
if os.path.exists('/www/server/nginx/sbin/nginx'):
result = execShell('/etc/init.d/nginx reload')
if result[1].find('nginx.pid') != -1:
execShell('pkill -9 nginx && sleep 1')
execShell('/etc/init.d/nginx start')
else:
result = execShell('/etc/init.d/httpd reload')
return result
def getNumLines(path, num, p=1):
pyVersion = sys.version_info[0]
try:
import cgi
if not os.path.exists(path):
return ""
start_line = (p - 1) * num
count = start_line + num
fp = open(path, 'rb')
buf = ""
fp.seek(-1, 2)
if fp.read(1) == "\n":
fp.seek(-1, 2)
data = []
b = True
n = 0
for i in range(count):
while True:
newline_pos = str.rfind(str(buf), "\n")
pos = fp.tell()
if newline_pos != -1:
if n >= start_line:
line = buf[newline_pos + 1:]
try:
data.insert(0, cgi.escape(line))
except:
pass
buf = buf[:newline_pos]
n += 1
break
else:
if pos == 0:
b = False
break
to_read = min(4096, pos)
fp.seek(-to_read, 1)
t_buf = fp.read(to_read)
if pyVersion == 3:
if type(t_buf) == bytes:
t_buf = t_buf.decode('utf-8')
buf = t_buf + buf
fp.seek(-to_read, 1)
if pos - to_read == 0:
buf = "\n" + buf
if not b:
break
fp.close()
except Exception as e:
return ''
def phpReload(version):
# 重载PHP配置
import os
if os.path.exists('/www/server/php/' + version + '/libphp5.so'):
execShell('/etc/init.d/httpd reload')
else:
execShell('/etc/init.d/php-fpm-' + version + ' reload')
return "\n".join(data)
def downloadFile(url, filename):
@@ -359,7 +530,7 @@ def downloadHook(count, blockSize, totalSize):
print '%02d%%' % (100.0 * count * blockSize / totalSize)
def GetLocalIp():
def getLocalIp():
# 取本地外网IP
try:
import re
@@ -376,13 +547,7 @@ def GetLocalIp():
ipaddress = re.search('\d+.\d+.\d+.\d+', ipaddress).group(0)
return ipaddress
except:
pass
# try:
# url = web.ctx.session.home + '/Api/getIpAddress'
# opener = urllib2.urlopen(url)
# return opener.read()
# except:
# return web.ctx.host.split(':')[0]
return '127.0.0.1'
def inArray(arrays, searchStr):
@@ -394,23 +559,6 @@ def inArray(arrays, searchStr):
return False
def checkWebConfig():
# 检查Web服务器配置文件是否有错误
if get_webserver() == 'nginx':
result = ExecShell(
"ulimit -n 10240 && /www/server/nginx/sbin/nginx -t -c /www/server/nginx/conf/nginx.conf")
searchStr = 'successful'
else:
result = ExecShell(
"ulimit -n 10240 && /www/server/apache/bin/apachectl -t")
searchStr = 'Syntax OK'
if result[1].find(searchStr) == -1:
WriteLog("TYPE_SOFT", 'CONF_CHECK_ERR', (result[1],))
return result[1]
return True
def checkIp(ip):
# 检查是否为IPv4地址
import re
@@ -424,7 +572,7 @@ def checkIp(ip):
def checkPort(port):
# 检查端口是否合法
ports = ['21', '25', '443', '8080', '888', '8888', '8443']
ports = ['21', '25', '443', '7200', '8080', '888', '8888', '8443']
if port in ports:
return False
intport = int(port)
@@ -463,33 +611,28 @@ def isRestart():
return True
def isUpdateLocalSoft():
num = M('tasks').where('status!=?', ('1',)).count()
if os.path.exists('mdserver-web.zip'):
return True
if num > 0:
data = M('tasks').where('status!=?', ('1',)).field(
'id,type,execstr').limit('1').select()
argv = data[0]['execstr'].split('|dl|')
if data[0]['type'] == 'download' and argv[1] == 'mdserver-web.zip':
return True
return False
def hasPwd(password):
# 加密密码字符
import crypt
return crypt.crypt(password, password)
def get_url(timeout=0.5):
import json
try:
nodeFile = '/www/server/panel/data/node.json'
node_list = json.loads(readFile(nodeFile))
mnode = None
for node in node_list:
node['ping'] = get_timeout(
node['protocol'] + node['address'] + ':' + node['port'] + '/check.txt')
if not node['ping']:
continue
if not mnode:
mnode = node
if node['ping'] < mnode['ping']:
mnode = node
return mnode['protocol'] + mnode['address'] + ':' + mnode['port']
except:
return 'http://download.bt.cn'
def get_timeout(url):
def getTimeout(url):
start = time.time()
result = httpGet(url)
if result != 'True':
@@ -497,6 +640,54 @@ def get_timeout(url):
return int((time.time() - start) * 1000)
def makeConf():
file = getRunDir() + '/data/json/config.json'
if not os.path.exists(file):
c = {}
c['title'] = 'Linux面板'
c['home'] = 'http://github/midoks/mdserver-web'
c['recycle_bin'] = True
c['template'] = 'default'
writeFile(file, json.dumps(c))
return c
c = readFile(file)
return json.loads(c)
def getConfig(k):
c = makeConf()
return c[k]
def setConfig(k, v):
c = makeConf()
c[k] = v
file = getRunDir() + '/data/json/config.json'
return writeFile(file, json.dumps(c))
def getHostAddr():
if os.path.exists('data/iplist.txt'):
return readFile('data/iplist.txt').strip()
return '127.0.0.1'
def setHostAddr(addr):
file = getRunDir() + '/data/iplist.txt'
return writeFile(file, addr)
def getHostPort():
if os.path.exists('data/port.pl'):
return readFile('data/port.pl').strip()
return '7200'
def setHostPort(port):
file = getRunDir() + '/data/port.pl'
return writeFile(file, port)
def auth_decode(data):
# 解密数据
token = GetToken()
@@ -570,14 +761,6 @@ def checkToken(get):
return True
def get_webserver():
# 获取Web服务器
webserver = 'nginx'
if not os.path.exists('/www/server/nginx/sbin/nginx'):
webserver = 'apache'
return webserver
def checkInput(data):
# 过滤输入
if not data:
@@ -598,54 +781,6 @@ def checkInput(data):
return data
def getNumLines(path, num, p=1):
# 取文件指定尾行数
try:
import cgi
if not os.path.exists(path):
return ""
start_line = (p - 1) * num
count = start_line + num
fp = open(path)
buf = ""
fp.seek(-1, 2)
if fp.read(1) == "\n":
fp.seek(-1, 2)
data = []
b = True
n = 0
for i in range(count):
while True:
newline_pos = string.rfind(buf, "\n")
pos = fp.tell()
if newline_pos != -1:
if n >= start_line:
line = buf[newline_pos + 1:]
try:
data.insert(0, cgi.escape(line))
except:
pass
buf = buf[:newline_pos]
n += 1
break
else:
if pos == 0:
b = False
break
to_read = min(4096, pos)
fp.seek(-to_read, 1)
buf = fp.read(to_read) + buf
fp.seek(-to_read, 1)
if pos - to_read == 0:
buf = "\n" + buf
if not b:
break
fp.close()
except:
data = []
return "\n".join(data)
def checkCert(certPath='ssl/certificate.pem'):
# 验证证书
openssl = '/usr/local/openssl/bin/openssl'
@@ -668,30 +803,38 @@ def checkCert(certPath='ssl/certificate.pem'):
return False
return True
# 获取面板地址
def getPathSize(path):
# 取文件或目录大小
if not os.path.exists(path):
return 0
if not os.path.isdir(path):
return os.path.getsize(path)
size_total = 0
for nf in os.walk(path):
for f in nf[2]:
filename = nf[0] + '/' + f
size_total += os.path.getsize(filename)
return size_total
# def getPanelAddr():
# import web
# protocol = 'https://' if os.path.exists("data/ssl.pl") else 'http://'
# h = web.ctx.host.split(':')
# try:
# result = protocol + h[0] + ':' + h[1]
# except:
# result = protocol + h[0] + ':' + readFile('data/port.pl').strip()
# return result
def to_size(size):
def toSize(size):
# 字节单位转换
d = ('b', 'KB', 'MB', 'GB', 'TB')
s = d[0]
for b in d:
if size < 1024:
return str(size) + ' ' + b
size = size / 1024
return str(round(size, 2)) + ' ' + b
size = float(size) / 1024.0
s = b
return str(size) + ' ' + b
return str(round(size, 2)) + ' ' + b
def getMacAddress():
# 获取mac
import uuid
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
return ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
def get_string(t):
@@ -731,3 +874,34 @@ def get_string_arr(t):
if s1 == s_arr[i][j]:
t_arr.append(str(i) + str(j))
return t_arr
def getSSHPort():
try:
file = '/etc/ssh/sshd_config'
conf = ReadFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
port = re.search(rep, conf).groups(0)[0]
return int(port)
except:
return 22
def getSSHStatus():
if os.path.exists('/usr/bin/apt-get'):
status = execShell("service ssh status | grep -P '(dead|stop)'")
else:
import system_api
version = system_api.system_api().getSystemVersion()
if version.find(' Mac ') != -1:
return True
if version.find(' 7.') != -1:
status = execShell("systemctl status sshd.service | grep 'dead'")
else:
status = execShell(
"/etc/init.d/sshd status | grep -e 'stopped' -e '已停'")
if len(status[0]) > 3:
status = False
else:
status = True
return status
+1702
View File
File diff suppressed because it is too large Load Diff
+194 -53
View File
@@ -8,9 +8,22 @@ import math
import json
from flask import Flask, session
from flask import request
import db
import public
import config_api
from threading import Thread
from time import sleep
def async(f):
def wrapper(*args, **kwargs):
thr = Thread(target=f, args=args, kwargs=kwargs)
thr.start()
return wrapper
class system_api:
@@ -18,9 +31,89 @@ class system_api:
pids = None
def __init__(self):
self.setupPath = '/www/server'
self.setupPath = public.getServerDir()
# 名取PID
##### ----- start ----- ###
def networkApi(self):
data = self.getNetWork()
return public.getJson(data)
def updateServerApi(self):
stype = request.args.get('type', 'check')
version = request.args.get('version', '')
return self.updateServer(stype, version)
def systemTotalApi(self):
data = self.getSystemTotal()
return public.getJson(data)
def diskInfoApi(self):
diskInfo = self.getDiskInfo()
return public.getJson(diskInfo)
def setControlApi(self):
stype = request.form.get('type', '')
day = request.form.get('day', '')
data = self.setControl(stype, day)
return data
def getLoadAverageApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getLoadAverageData(start, end)
return public.getJson(data)
def getCpuIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getCpuIoData(start, end)
return public.getJson(data)
def getDiskIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getDiskIoData(start, end)
return public.getJson(data)
def getNetworkIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getNetWorkIoData(start, end)
return public.getJson(data)
def rememoryApi(self):
os.system('sync')
scriptFile = public.getRunDir() + '/script/rememory.sh'
public.execShell("/bin/bash " + scriptFile)
data = self.getMemInfo()
return public.getJson(data)
# 重启面板
def restartApi(self):
self.restartMw()
return public.returnJson(True, '面板已重启!')
def restartServerApi(self):
if public.isAppleSystem():
return public.returnJson(False, "开发环境不可重起")
self.restartServer()
return public.returnJson(True, '正在重启服务器!')
##### ----- end ----- ###
@async
def restartMw(self):
sleep(1)
cmd = public.getRunDir() + '/scripts/init.d/mw reload'
public.execShell(cmd)
@async
def restartServer(self):
if not public.isRestart():
return public.returnJson(False, '请等待所有安装任务完成再执行!')
public.execShell("sync && init 6 &")
return public.returnJson(True, '命令发送成功!')
# 名取PID
def getPid(self, pname):
try:
if not self.pids:
@@ -99,7 +192,7 @@ class system_api:
data['version'] = '0.0.1'
return data
def getLoadAverage(self, get=None):
def getLoadAverage(self):
c = os.getloadavg()
data = {}
data['one'] = float(c[0])
@@ -116,7 +209,7 @@ class system_api:
data['title'] = self.GetTitle()
data['network'] = self.GetNetWorkApi(get)
data['panel_status'] = not os.path.exists(
'/www/server/panel/data/close.pl')
'/www/server/mdserver-web/data/close.pl')
import firewalls
ssh_info = firewalls.firewalls().GetSshInfo(None)
data['enable_ssh_status'] = ssh_info['status']
@@ -129,15 +222,14 @@ class system_api:
def getTitle(self):
titlePl = 'data/title.pl'
title = '宝塔Linux面板'
title = 'Linux面板'
if os.path.exists(titlePl):
title = public.readFile(titlePl).strip()
return title
def getSystemVersion(self):
# 取操作系统版本
os = public.getOs()
if os == 'darwin':
if public.getOs() == 'darwin':
data = public.execShell('sw_vers')[0]
data_list = data.strip().split("\n")
mac_version = ''
@@ -172,7 +264,7 @@ class system_api:
used = psutil.cpu_percent(interval=interval)
return used, cpuCount
def getMemInfo(self, get=None):
def getMemInfo(self):
# 取内存信息
mem = psutil.virtual_memory()
if public.getOs() == 'darwin':
@@ -311,10 +403,10 @@ class system_api:
# 清理其它
def clearOther(self):
clearPath = [
{'path': '/www/server/panel', 'find': 'testDisk_'},
{'path': '/www/server/mdserver-web', 'find': 'testDisk_'},
{'path': '/www/wwwlogs', 'find': 'log'},
{'path': '/tmp', 'find': 'panelBoot.pl'},
{'path': '/www/server/panel/install', 'find': '.rpm'}
{'path': '/www/server/mdserver-web/install', 'find': '.rpm'}
]
total = count = 0
@@ -334,7 +426,7 @@ class system_api:
os.system('echo > /tmp/panelBoot.pl')
return total, count
def getNetWork(self, get=None):
def getNetWork(self):
# return self.GetNetWorkApi(get);
# 取网络流量信息
try:
@@ -362,15 +454,15 @@ class system_api:
session['otime'] = time.time()
networkInfo['cpu'] = self.getCpuInfo()
networkInfo['load'] = self.getLoadAverage(get)
networkInfo['mem'] = self.getMemInfo(get)
networkInfo['load'] = self.getLoadAverage()
networkInfo['mem'] = self.getMemInfo()
return networkInfo
except Exception, e:
print e
return None
def getNetWorkApi(self, get=None):
def getNetWorkApi(self):
# 取网络流量信息
try:
tmpfile = 'data/network.temp'
@@ -401,23 +493,6 @@ class system_api:
except:
return None
def restartServer(self, get):
if not public.IsRestart():
return public.returnMsg(False, 'EXEC_ERR_TASK')
public.ExecShell("sync && /etc/init.d/bt stop && init 6 &")
return public.returnMsg(True, 'SYS_REBOOT')
# 释放内存
def reMemory(self, get):
os.system('sync')
scriptFile = 'script/rememory.sh'
if not os.path.exists(scriptFile):
public.downloadFile(web.ctx.session.home +
'/script/rememory.sh', scriptFile)
public.ExecShell("/bin/bash " + self.setupPath +
'/panel/' + scriptFile)
return self.GetMemInfo()
def getNetWorkIoData(self, start, end):
# 取指定时间段的网络Io
data = public.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
@@ -515,38 +590,104 @@ class system_api:
return public.returnJson(True, "设置成功!")
# 更新服务
def updateServer(self, stype):
def versionDiff(self, old, new):
'''
test 测试
new 有新版本
none 没有新版本
'''
new_list = new.split('.')
if len(new_list) > 3:
return 'test'
old_list = old.split('.')
ret = 'none'
for i in range(len(old_list)):
tm_new = int(new_list[i])
tm_old = int(new_list[i])
if tm_new > tm_old:
return 'new'
return ret
def getServerInfo(self):
upAddr = 'https://raw.githubusercontent.com/midoks/mdserver-web/master/version/info.json'
try:
version = public.httpGet(upAddr)
print version
version = json.loads(version)
return version[0]
except Exception as e:
print 'getServerInfo', e
return {}
def updateServer(self, stype, version=''):
# 更新服务
try:
if not public.isRestart():
return public.returnMsg(False, '请等待所有安装任务完成再执行!')
if stype == 'check':
public.httpGet('')
except Exception as ex:
return public.returnJson(False, "连接服务器失败!")
return public.returnJson(False, '请等待所有安装任务完成再执行!')
# 重启面板
def reWeb(self, get):
# if not public.IsRestart(): return
# public.returnMsg(False,'EXEC_ERR_TASK');
# public.ExecShell('/etc/init.d/bt restart &')
return True
if stype == 'check':
version_now = config_api.config_api().getVersion()
version_new_info = self.getServerInfo()
if not 'version' in version_new_info:
return public.returnJson(False, '服务器数据有问题!')
diff = self.versionDiff(
version_now, version_new_info['version'])
if diff == 'new':
return public.returnJson(True, '有新版本!', version_new_info['version'])
elif diff == 'test':
return public.returnJson(True, '有测试版本!', version_new_info['version'])
else:
return public.returnJson(False, '已经是最新,无需更新!')
if stype == 'info':
version_new_info = self.getServerInfo()
version_now = config_api.config_api().getVersion()
if not 'version' in version_new_info:
return public.returnJson(False, '服务器数据有问题!')
diff = self.versionDiff(
version_now, version_new_info['version'])
return public.returnJson(True, '更新信息!', version_new_info)
if stype == 'update':
if version == '':
return public.returnJson(False, '缺少版本信息!')
v_new_info = self.getServerInfo()
if v_new_info['version'] != version:
return public.returnJson(False, '更新失败,请重试!')
if not 'path' in v_new_info or v_new_info['path'] == '':
return public.returnJson(False, '下载地址不存在!')
newUrl = v_new_info['path']
toPath = public.getRootDir() + '/temp'
if not os.path.exists(toPath):
public.execShell('mkdir -p ' + toPath)
if not os.path.exists(toPath + '/mw.zip'):
public.execShell('wget -O ' + toPath + '/mw.zip ' + newUrl)
public.execShell('unzip -o ' + toPath + '/mw.zip' + ' -d ./')
public.execShell('unzip -o mdserver-web.zip -d ./')
public.execShell('rm -f mdserver-web.zip')
return public.returnJson(True, '安装更新成功!')
return public.returnJson(False, '已经是最新,无需更新!')
except Exception as ex:
print 'updateServer', ex
return public.returnJson(False, "连接服务器失败!")
# 修复面板
def repPanel(self, get):
vp = ''
if public.readFile('/www/server/panel/class/common.py').find('checkSafe') != -1:
if public.readFile('/www/server/mdserver-web/class/common.py').find('checkSafe') != -1:
vp = '_pro'
public.ExecShell("wget -O update.sh " + public.get_url() +
"/install/update" + vp + ".sh && bash update.sh")
if hasattr(web.ctx.session, 'getCloudPlugin'):
del(web.ctx.session['getCloudPlugin'])
return True
# 升级到专业版
def updatePro(self, get):
public.ExecShell("wget -O update.sh " + public.get_url() +
"/install/update_pro.sh && bash update.sh pro")
if hasattr(web.ctx.session, 'getCloudPlugin'):
del(web.ctx.session['getCloudPlugin'])
return True
+86
View File
@@ -0,0 +1,86 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
from flask import request
class task_api:
def __init__(self):
pass
def countApi(self):
c = public.M('tasks').where("status!=?", ('1',)).count()
return str(c)
def listApi(self):
p = request.form.get('p', '1').encode('utf-8')
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
start = (int(p) - 1) * int(limit)
limit_str = str(start) + ',' + str(limit)
_list = public.M('tasks').where('', ()).field(
'id,name,type,status,addtime,start,end').limit(limit_str).order('id desc').select()
_ret = {}
_ret['data'] = _list
count = public.M('tasks').where('', ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'remind'
_page['p'] = p
_ret['page'] = public.getPage(_page)
return public.getJson(_ret)
def getExecLogApi(self):
file = os.getcwd() + "/tmp/panelExec.log"
v = public.getLastLine(file, 100)
return v
def getTaskSpeedApi(self):
tempFile = os.getcwd() + '/tmp/panelExec.log'
freshFile = os.getcwd() + '/tmp/panelFresh'
find = public.M('tasks').where('status=? OR status=?',
('-1', '0')).field('id,type,name,execstr').find()
if not len(find):
return public.returnJson(False, '当前没有任务队列在执行-2!')
isTask = os.getcwd() + '/tmp/panelTask.pl'
public.writeFile(isTask, 'True')
echoMsg = {}
echoMsg['name'] = find['name']
echoMsg['execstr'] = find['execstr']
if find['type'] == 'download':
import json
try:
tmp = public.readFile(tempFile)
if len(tmp) < 10:
return public.returnJson(False, '当前没有任务队列在执行-3!')
echoMsg['msg'] = json.loads(tmp)
echoMsg['isDownload'] = True
except:
public.M('tasks').where(
"id=?", (find['id'],)).save('status', ('0',))
return public.returnJson(False, '当前没有任务队列在执行-4!')
else:
echoMsg['msg'] = public.getLastLine(tempFile, 10)
echoMsg['isDownload'] = False
echoMsg['task'] = public.M('tasks').where("status!=?", ('1',)).field(
'id,status,name,type').order("id asc").select()
return public.getJson(echoMsg)
Executable
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/local/lib/python2.7/bin
mw_start(){
gunicorn -c setting.py app:app
python task.py &
}
mw_start_debug(){
python task.py &
gunicorn -b :7200 -k gevent -w 1 app:app
# gunicorn -b :7200 -k eventlet -w 1 app:app
# gunicorn -c setting.py app:app
}
mw_stop()
{
ps -ef|grep app:app |grep -v grep|awk '{print $2}'|xargs kill -9
ps -ef|grep task.py |grep -v grep|awk '{print $2}'|xargs kill -9
}
case "$1" in
'start') mw_start;;
'stop') mw_stop;;
'restart')
mw_stop
mw_start
;;
'debug')
mw_stop
mw_start_debug
;;
esac
-1
View File
@@ -1 +0,0 @@
30
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
qpzw99oc
+1 -1
View File
@@ -10,7 +10,7 @@
"ps":""
},
{
"title":"缓存软件",
"title":"数据软件",
"type":2,
"ps":""
},
Executable
+1
View File
@@ -0,0 +1 @@
7200
+1
View File
@@ -0,0 +1 @@
True
+23 -40
View File
@@ -19,19 +19,6 @@ CREATE TABLE IF NOT EXISTS `binding` (
);
CREATE TABLE IF NOT EXISTS `config` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`webserver` TEXT,
`backup_path` TEXT,
`sites_path` TEXT,
`status` INTEGER,
`mysql_root` TEXT
);
INSERT INTO `config` (`id`, `webserver`, `backup_path`, `sites_path`, `status`, `mysql_root`) VALUES
(1, 'nginx', '/www/backup', '/www/wwwroot', 0, 'admin');
CREATE TABLE IF NOT EXISTS `crontab` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT,
@@ -40,18 +27,14 @@ CREATE TABLE IF NOT EXISTS `crontab` (
`where_hour` INTEGER,
`where_minute` INTEGER,
`echo` TEXT,
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `databases` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
`name` TEXT,
`username` TEXT,
`password` TEXT,
`accept` TEXT,
`ps` TEXT,
`addtime` TEXT
`addtime` TEXT,
`status` INTEGER DEFAULT '1',
`save` INTEGER DEFAULT '3',
`backup_to` TEXT DEFAULT 'off',
`sname` TEXT,
`sbody` TEXT,
'stype' TEXT,
`urladdress` TEXT
);
CREATE TABLE IF NOT EXISTS `firewall` (
@@ -62,23 +45,12 @@ CREATE TABLE IF NOT EXISTS `firewall` (
);
INSERT INTO `firewall` (`id`, `port`, `ps`, `addtime`) VALUES
(2, '80', '网站默认端口', '0000-00-00 00:00:00'),
(3, '8888', 'WEB面板', '0000-00-00 00:00:00'),
(4, '21', 'FTP服务', '0000-00-00 00:00:00'),
(5, '22', 'SSH远程管理服务', '0000-00-00 00:00:00');
(1, '80', '网站默认端口', '0000-00-00 00:00:00'),
(2, '7200', 'WEB面板', '0000-00-00 00:00:00'),
(3, '22', 'SSH远程管理服务', '0000-00-00 00:00:00')
(3, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00');
CREATE TABLE IF NOT EXISTS `ftps` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
`name` TEXT,
`password` TEXT,
`path` TEXT,
`status` TEXT,
`ps` TEXT,
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `logs` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -94,6 +66,7 @@ CREATE TABLE IF NOT EXISTS `sites` (
`status` TEXT,
`index` TEXT,
`ps` TEXT,
`edate` TEXT,
`addtime` TEXT
);
@@ -129,3 +102,13 @@ CREATE TABLE IF NOT EXISTS `tasks` (
`end` INTEGER,
`execstr` TEXT
);
CREATE TABLE IF NOT EXISTS `panel` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`title` TEXT,
`url` TEXT,
`username` TEXT,
`password` TEXT,
`click` INTEGER,
`addtime` INTEGER
);
+52
View File
@@ -0,0 +1,52 @@
server
{
listen {$PORT};
server_name {$SERVER_NAME};
index index.php index.html index.htm default.php default.htm default.html;
root {$ROOT_DIR};
#SSL-START
#error_page 404/404.html;
#SSL-END
#ERROR-PAGE-START
error_page 404 /404.html;
error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START
include enable-php-{$PHPVER}.conf;
#PHP-INFO-END
#REWRITE-START
include {$OR_REWRITE}/{$SERVER_NAME}.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log /dev/null;
}
location ~ .*\\.(js|css)?$
{
expires 12h;
error_log off;
access_log /dev/null;
}
access_log {$LOGPATH}/{$SERVER_NAME}.log;
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
}
+55
View File
@@ -0,0 +1,55 @@
#BINDING-{$DIRBIND}-START
server
{
listen {$PORT};
server_name {$DIRBIND};
index index.php index.html index.htm default.php default.htm default.html;
root {$ROOT_DIR};
#SSL-START
#error_page 404/404.html;
#SSL-END
#ERROR-PAGE-START
error_page 404 /404.html;
error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START
include enable-php-{$PHPVER}.conf;
#PHP-INFO-END
#REWRITE-START
include {$OR_REWRITE}/{$SERVER_MAIN}.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log /dev/null;
}
location ~ .*\\.(js|css)?$
{
expires 12h;
error_log off;
access_log /dev/null;
}
access_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.log;
error_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.error.log;
}
#BINDING-{$DIRBIND}-END
-6
View File
@@ -1,6 +0,0 @@
#!/bin/sh
rm -rf ./*.pyc
rm -rf ./*/*.pyc
#open "http://127.0.0.1:7200"
Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

+16
View File
@@ -0,0 +1,16 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('abkill');">服务</p>
<p onclick="pluginInitD('abkill');">自启动</p>
<p onclick="pluginConfig('abkill');">黑名单</p>
<p onclick="pluginConfig('abkill');">异常日志</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=abkill&f=js/abkill.js");
</script>
+172
View File
@@ -0,0 +1,172 @@
# coding: utf-8
import time
import random
import os
import urllib
import binascii
import json
import re
import sys
import subprocess
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.getOs() == 'darwin':
app_debug = True
def getPluginName():
return 'abkill'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def initDreplace():
initd_file = getInitDFile()
if not os.path.exists(initd_file):
return getServerDir()
return initd_file
def status():
data = public.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def csvnOp(method):
if app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
#_csvn = getServerDir() + '/bin/csvn'
#_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn_httpd = public.execShell(_initd_csvn_httpd + ' ' + method)
# ret_csvn = public.execShell(_initd_csvn + ' ' + method)
subprocess.Popen(_initd_csvn + ' ' + method,
stdout=subprocess.PIPE, shell=True)
if ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def start():
return csvnOp('start')
def stop():
return csvnOp('stop')
def restart():
return csvnOp('restart')
def reload():
return csvnOp('reload')
def initdStatus():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
if os.path.exists(_initd_csvn) and os.path.exists(_initd_csvn_httpd):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' install')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' install')
if ret_csvn[1] == '' and ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def initdUinstall():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' remove')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' remove')
return 'ok'
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()
else:
print 'fail'
+16
View File
@@ -0,0 +1,16 @@
{
"sort": 7,
"ps": "异常程序监控和KILL",
"shell": "install.sh",
"name": "abkill",
"title": "异常程序监控",
"versions": "0.1",
"updates":"0.1",
"tip": "soft",
"checks": "server/abkill",
"author": "midoks",
"date": "201-04-01",
"home": "https://www.collab.net",
"type": "异常程序监控和KILL",
"pid": "4"
}
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
ak_path={$SERVER_PATH}/abkill
ak_start(){
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "Starting abkill... \c"
cd $ak_path && nohup python abkill.py >> $ak_path/task.log 2>&1 &
sleep 0.3
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $ak_path/task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: abkill service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting abkill(pid $isStart) already running"
fi
}
ak_stop()
{
echo -e "Stopping abkill... \c";
pids=$(ps aux | grep 'abkill.py' | grep -v grep|awk '{print $2}')
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p
done
echo -e "\033[32mdone\033[0m"
}
ak_status()
{
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" != '' ];then
echo -e "\033[32mabkill (pid $(echo $isStart)) already running\033[0m"
else
echo -e "\033[31mabkill not running\033[0m"
fi
}
ak_reload()
{
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" != '' ];then
ak_stop
ak_start
else
echo -e "\033[31mmw not running\033[0m"
mw_start
fi
}
case "$1" in
'start') ak_start;;
'stop') ak_stop;;
'reload') ak_reload;;
'restart')
ak_stop
sleep 0.3
ak_start;;
'status') ak_status;;
esac
@@ -7,24 +7,26 @@ rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/bt_install.pl
Install_readme()
Install_abkill()
{
mkdir -p ${serverPath}/readme
echo "${1}" > ${serverPath}/readme/version.pl
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/abkill
echo '0.1' > $serverPath/abkill/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_readme()
Uninstall_abkill()
{
rm -rf ${serverPath}/readme
echo '卸载完成' > $install_tmp
rm -f $serverPath/abkill
echo "卸载完成" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_readme $2
Install_abkill
else
Uninstall_readme $2
Uninstall_abkill
fi
+1
View File
@@ -0,0 +1 @@
pluginService('abkill');
@@ -31,12 +31,12 @@ class btkill:
if cputimes.user < 0.1:
continue
print p
percent = p.cpu_percent(interval=0.1)
percent = p.cpu_percent(interval=1)
vm = p.memory_info().vms
if percent > self.__limit or vm > self.__vmsize:
log = time.strftime('%Y-%m-%d %X', time.localtime()) + " (PID=" + str(
pid) + ", NAME=" + name + ", VMS=" + str(vm) + ", PERCENT=" + str(percent) + "%)"
p.kill()
# p.kill()
num += 1
print log + " >> killed\n"
except Exception as ex:
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
export LC_ALL=en_US.UTF-8
export LC_CTYPE=zh_CN.UTF-8
REPOS="$1"
REV="$2"
TXN_NAME="$3"
if [ ! -d {$PROJECT_DIR}/csvn ]; then
sudo mkdir -p {$PROJECT_DIR}/csvn
sudo chown -R csvn:csvn {$PROJECT_DIR}/csvn
fi
SAVE_PATH={$PROJECT_DIR}/csvn/$REPOS
SVN_PATH=http://127.0.0.1:{$PORT}/svn/$REPOS
if [ ! -d $SAVE_PATH ]; then
svn co $SVN_PATH $SAVE_PATH \
--username={$CSVN_USER} \
--password={$CSVN_PWD} \
--no-auth-cache \
--non-interactive
fi
cd $SAVE_PATH && svn update --username={$CSVN_USER} --password={$CSVN_PWD} --no-auth-cache --non-interactive
WEB_PATH={$PROJECT_DIR}/wwwroot/$REPOS
sudo mkdir -p $WEB_PATH
sudo rsync -vauP --delete --exclude=".*" $SAVE_PATH/ $WEB_PATH
sudo chown -R www:www $WEB_PATH
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
REPOS="$1"
REV="$2"
TXN_NAME="$3"
REPOS_NAME=${REPOS##*/}
sh -x $REPOS/hooks/commit $REPOS_NAME $REV $TXN_NAME 2>$REPOS/sh.log
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+28 -540
View File
@@ -1,550 +1,38 @@
<style>
/*危险按钮*/
.bts-danger:hover{
color: #fff;
background-color: #c9302c;
border-color: #ac2925;
}
#whiteList a{
color: red;
}
/*弹窗*/
.Add_view{
height: 100px;
padding-left: 35px;
padding-top: 35px;
}
.Add_view label{
margin-right: 10px;
font-size: 15px;
font-weight: 100;
}
.Add_view input{
width: 230px;
}
.Add_view .error{
border: 1px solid red;
}
.Add_view .correct{
border: 1px solid #20a53a;
}
/*日志管理*/
.btnTitle{
font-weight: 100;
font-size: 16px;
line-height: 34px;
height: 34px;
margin-right: 15px;
position: relative;
top: 2px;
}
.whiteList-table{
margin-top: 10px;
}
/*登录日志表单*/
.viewTwo .whiteList-table{
overflow-x: hidden;
height: 500px;
}
.maks{
background: rgba(39, 39, 39, 0.4);
position: absolute;
width: 700px;
height: 555px;
z-index: 999;
overflow: hidden;
}
.boxshow{
position: absolute;
height: 150px;
width: 400px;
margin-left: -200px;
margin-top: -75px;
left: 50%;
top: 50%;
z-index: 1000;
background: #fff;
padding: 25px 20px;
overflow: hidden;
}
.btPayment {
float: left;
padding: 8px 10px;
width: 190px;
height: 100px;
line-height: 33px;
text-align: center;
border-left: 1px solid #ececec;
}
.btPayment .t2{
display: block;
width: 100%;
text-align: center;
font-size: 16px;
margin-bottom: 5px;
}
.btPayment .price{
color: #20A53A;
font-size: 22px;
margin: 0 5px;
}
.bt-form{
overflow: hidden;
}
.boxtext{
line-height: 32px;
margin-top: -17px;
text-align: center;
border-bottom: #eee 1px solid;
height: 39px;
font-size: 14px;
<style type="text/css">
.outline_no {
outline:none;
}
</style>
<div class="maks" style="display: none"></div>
<div class="boxshow" style="display: none;">
<div>
<div class="boxtext">
<span>未开通此服务,如需使用请开通企业运维版。</span>
</div>
<div class="btvipinfo" style="width: 170px;padding-left: 20px">
<p style="height: 25px">1、一对一运维人员对接</p>
<p style="height: 25px">2、提供每月3次运维服务</p>
<p style="height: 25px">3、双重安全隔离登录</p>
</div>
<div class="btPayment">
<span class="t2">企业运维版<span class="price">98</span>元/月</span>
<button class="btn btn-success btn-sm" style="width:80%" onclick="window.open('https://www.bt.cn/admin/index.html')">立即开通</button>
</div>
</div>
</div>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw">密钥</p>
<p>面板设置</p>
<p>面板登录日志</p>
<p>SSH设置</p>
<p>SSH日志管理</p>
<p class="bgw" onclick="pluginService('csvn');">服务</p>
<p onclick="pluginInitD('csvn');">自启动</p>
<p onclick="csvnEdit();">手动编辑</p>
<p onclick="csvnUserList(1);">用户管理</p>
<p onclick="csvnProjectList(1);">项目管理</p>
<p onclick="csvnReadme();">使用说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con viewZoo">
<p class="status" style="margin-top:10px;margin-left:10px;height: 80px;margin-bottom:15px;">
<span style="float:left;margin-top:-5px">密钥:</span>
<textarea class="bt-input-text" name="token" readonly="readonly" style="background-color: #eee;width:400px;height:80px;padding: 8px 15px;" placeholder="密钥已隐藏..."></textarea>
</p>
<input type="button" class="btn btn-success btn-sm" name="ButtonShow" style="margin-left:52px;width:100px" onclick="sagelogin.tokenShow()" value="显示密钥" />
<ul style="margin: 15px 5px;padding-left: 70px;list-style-type: disc;line-height: 25px;">
<li>宝塔企业运维后台连接您的服务器需要此密钥,请妥善记录并保存</li>
<li>一但密钥丢失,可能导致您无法登录服务器</li>
</ul>
</div>
<div class="soft-man-con viewOne" style="display: none;">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play"></span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除面板登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('面板白名单',true)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListOne"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewTwo" style="display: none">
<div class="whiteList-table divtable">
<table class="table table-hover" style=" max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>操作记录</th>
<th>操作时间</th>
</tr>
</thead>
<tbody id="whiteListTwo"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewThree" style="display: none">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play">
</span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除SSH登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('SSH白名单',false)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListThree"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewFour" style="display: none">
<div class="btnclick">
<label class="btnTitle">日志分类</label>
<div class="btn-group">
<input type="submit" name="btnOne" class="btn btn-success" onclick="sagelogin.SSH_Defense_List(0)" value="已防御" />
<input type="submit" name="btnTwo" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(1)" value="入侵日志"/>
<input type="submit" name="btnThree" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(2)" value="登录日志"/>
</div>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 470px;">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>源IP地址</th>
<th>用户</th>
<th style="text-align: right;">登录时间</th>
</tr>
</thead>
<tbody id="whiteListFour"></tbody>
</table>
</div>
</div>
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="javascript/text">
//宝塔安全登录
$(function(){
$(".bt-w-menu p").click(function(){
$(this).addClass("bgw").siblings().removeClass("bgw");
$('.bt-w-con .soft-man-con').hide().eq($(this).index()).show();
switch($(this).index()) {
case 0:
break;
case 1:
sagelogin.Panel_White_List();
break;
case 2:
sagelogin.Panel_journal();
break;
case 3:
sagelogin.SSH_White_List();
break;
case 4:
sagelogin.SSH_Defense_List(0);
break;
}
});
layer.load();
$.get('/plugin?action=a&name=safelogin&s=GetServerInfo',function(data) {
layer.closeAll('loading');
if (data.status) {
$('.boxshow').hide();
$('.maks').hide();
}else{
$('.boxshow').show();
$('.maks').show();
}
});
});
var sagelogin = new Object();
sagelogin = {
Addview:'',
SSHlogList:'',
PanelLogList:'',
// SSH管理
SSH_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?',{icon: 1}, {
btn: ['确认','取消'],
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_ssh_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.SSH_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
tokenShow:function(){
var inputPwd = layer.open({
type: 1,
title: '验证面板密码',
shadeClose: true,
shade: 0.3,
area: ['380px', '190px'],
btn:['确定','取消'],
content:'<div class="Add_view" style="height:90px"><label>面板密码:</label><input name="panel_pwd" class=" bt-input-text" type="password"></div>',
yes:function(){
var passwordStr = $("input[name='panel_pwd']").val();
var index = layer.load(0, {shade: false});
$.post('/plugin?action=a&name=safelogin&s=GetServerToken',{password:passwordStr},function(token) {
layer.close(index);
if(token.status === false){
layer.msg(token.msg,{icon:2});
return;
}
layer.close(inputPwd);
$("textarea[name='token']").val(token);
});
},
btn2:function(){
layer.close(inputPwd);
}
});
},
// SSH白名单——列表
SSH_White_List:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_ssh_limit','',function(data){
$('#whiteListThree').empty();
var List = '';
if (data.length == 0){
$('.viewThree .status span:eq(0)').html('关闭');
$('.viewThree .glyphicon-pause').show();
$('.viewThree .glyphicon-play').hide();
}else {
$('.viewThree .status span:eq(0)').html('开启');
$('.viewThree .glyphicon-pause').hide();
$('.viewThree .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.SSH_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListThree').append(List);
layer.close(index);
});
},
// SSH白名单——删除
SSH_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// SSH白名单——添加
SSH_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_ssh_limit',{ip:ip},function(data){
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// SSH日志管理
SSH_Defense_List:function(status){
$('.btnclick input').removeClass('btn-success').addClass('btn-default');
$('.btnclick input').eq(status).addClass('btn-success').removeClass('btn-default');
if (sagelogin.SSHlogList == '') {
$.get('/plugin?action=a&s=get_ssh_errorlogin&name=safelogin',function(data){
sagelogin.SSHlogList = data;
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
});
}else{
switch(status) {
case 0:
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
break;
case 1:
sagelogin.DefenseFor(sagelogin.SSHlogList.intrusion);
break;
case 2:
sagelogin.DefenseFor(sagelogin.SSHlogList.success);
break;
}
}
},
// SSH日志渲染模板
DefenseFor:function(data){
var List = '';
$('#whiteListFour').empty();
for (var i = data.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+data[i].address+'</td><td>' + data[i].user + '</td><td style="text-align:right">'+ data[i].date+'</td></tr>'
}
$('#whiteListFour').append(List);
},
// 面板管理
Panel_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_panel_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.Panel_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——列表
Panel_White_List:function(){
$.get('/plugin?action=a&name=safelogin&s=get_panel_limit','',function(data){
$('#whiteListOne').empty();
var List = '';
if (data.length == 0){
$('.viewOne .status span:eq(0)').html('关闭');
$('.viewOne .glyphicon-pause').show();
$('.viewOne .glyphicon-play').hide();
}else {
$('.viewOne .status span:eq(0)').html('开启');
$('.viewOne .glyphicon-pause').hide();
$('.viewOne .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.Panel_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListOne').append(List);
});
},
// 面板白名单——删除
Panel_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——添加
Panel_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_panel_limit', {ip: ip}, function(data) {
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// 面板日志——列表
Panel_journal:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_login_log',function(data){
$('#whiteListTwo').empty();
var List = '';
sagelogin.PanelLogList = data;
for (var i = sagelogin.PanelLogList.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+ sagelogin.PanelLogList[i].log +'</td><td style="text-align:right;">'+ sagelogin.PanelLogList[i].addtime +'</tr>';
}
$('#whiteListTwo').append(List);
layer.close(index);
});
},
// IP正则:192.168.1.0/24
CheckIP:function(ip) {
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\/\d{1,2})?$/;
return reg.test(ip);
},
CheckIPTwo:function(ip) {
var reg = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/gi;
return reg.test(ip);
},
// 添加表单效验
addViewVul:function(status){
var ip = $('.addViewVul');
if (status) {
console.log(sagelogin.CheckIP(ip.val()));
if(sagelogin.CheckIPTwo(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}else{
if(sagelogin.CheckIP(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}
},
// 添加界面
Add_view:function(title,status){
var _this = this;
var text = ''
var statuss = true;
if (status) {
text = '';
statuss = true;
}else{
text = '<p style="color:red;margin: 5px 0px 0px 67px;font-size: 14px;">支持IP段,如:192.168.1.0/24</p>';
statuss = false;
}
sagelogin.Addview = layer.open({
type: 1,
title: title,
shadeClose: true,
shade: 0.1,
area: ['380px', '200px'],
btn:['确定','取消'],
content:'<div class="Add_view"><label>IP地址:</label><input class="addViewVul bt-input-text" onchange="sagelogin.addViewVul('+ statuss +')" type="text">'+ text +'</div>',
yes:function(){
if (sagelogin.addViewVul(statuss)) {
if(status){
sagelogin.Panel_Add_White_List($('.addViewVul').val());
}else{
sagelogin.SSH_Add_White_List($('.addViewVul').val());
}
}else{
layer.msg('请输入合法的IP地址',{icon:2})
}
},
btn2:function(){
layer.close(sagelogin.Addview);
}
});
$('.addViewVul').focus();
}
}
</script>
</div>
<script type="text/javascript">
resetPluginWinWidth(700);
$.getScript( "/plugins/file?name=csvn&f=js/csvn.js");
function csvnReadme(){
var html = '<p>* 注意:在启动时会比较慢,需要耐心等待一会</p>';
html += '<p>* 注意:csvn需要java环境,在安装会自动检查并安装</p>';
html += '<p>* 注意:默认后台密码admin:admin,最好马上修改</p>';
html += '<p>* 注意:牢记admin的密码,在后csvn的管理后台和这里不同步</p>';
html += '<p>* 注意:在这里添加用户和csvn后台并不同步</p>';
html += '<p>* 注意:项目管理的地址一般是正确的,但在特殊环境下,地址可能不一致</p>';
html += '<p>* 注意:脚本内使用sudo名,需要注释(vi /etc/sudoers)[#Default requiretty]</p>';
$('.bt-w-main .soft-man-con').html(html);
}
</script>
+691 -2
View File
@@ -1,20 +1,709 @@
# coding: utf-8
import time
import psutil
import random
import os
import urllib
import binascii
import json
import public
import re
import sys
import subprocess
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.isAppleSystem():
app_debug = True
def getPluginName():
return 'csvn'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def initDreplace():
initd_file = getInitDFile()
if not os.path.exists(initd_file):
return getServerDir()
return initd_file
def status():
data = public.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def csvnOp(method):
if app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
#_csvn = getServerDir() + '/bin/csvn'
#_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn_httpd = public.execShell(_initd_csvn_httpd + ' ' + method)
# ret_csvn = public.execShell(_initd_csvn + ' ' + method)
subprocess.Popen(_initd_csvn + ' ' + method,
stdout=subprocess.PIPE, shell=True)
if ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def start():
return csvnOp('start')
def stop():
return csvnOp('stop')
def restart():
return csvnOp('restart')
def reload():
return csvnOp('reload')
def initdStatus():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
if os.path.exists(_initd_csvn) and os.path.exists(_initd_csvn_httpd):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' install')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' install')
if ret_csvn[1] == '' and ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def initdUinstall():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' remove')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' remove')
return 'ok'
def csvnEdit():
data = {}
data['svn_access_file'] = getServerDir() + '/data/conf/svn_access_file'
data['commit_tpl'] = getPluginDir() + '/hook/commit.tpl'
data['post_commit_tpl'] = getPluginDir() + '/hook/post-commit.tpl'
return public.getJson(data)
def userAdd():
args = getArgs()
if not 'username' in args:
return 'name missing'
if not 'password' in args:
return 'password missing'
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -b ' + svn_auth_file + ' ' + \
args['username'] + ' ' + args['password']
data = public.execShell(cmd)
# print data
if data[0] == '':
return 'ok'
return 'fail'
def userDel():
args = getArgs()
if not 'username' in args:
return 'name missing'
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -D ' + svn_auth_file + ' ' + args['username']
data = public.execShell(cmd)
if data[0] == '':
return 'ok'
return 'fail'
def getAllUser(search=''):
svn_auth_file = getServerDir() + '/data/conf/svn_auth_file'
if not os.path.exists(svn_auth_file):
return public.getJson([])
auth = public.readFile(svn_auth_file)
auth = auth.strip()
auth_list = auth.split("\n")
ulist = []
for x in range(len(auth_list)):
tmp = auth_list[x].split(':')
if search != '':
if tmp[0].find(search) != -1:
ulist.append(tmp[0])
else:
ulist.append(tmp[0])
return ulist
def userList():
import math
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
ulist = getAllUser(search)
ulist_sum = len(ulist)
page_info = {'count': ulist_sum, 'p': page,
'row': 10, 'tojs': 'csvnUserList'}
data = {}
data['list'] = public.getPage(page_info)
data['page'] = page
data['page_size'] = page_size
data['page_count'] = int(math.ceil(ulist_sum / page_size))
start = (page - 1) * page_size
data['data'] = ulist[start:start + page_size]
return public.getJson(data)
def projectAdd():
args = getArgs()
if not 'name' in args:
return 'project name missing'
path = getServerDir() + '/bin/svnadmin'
dest = getServerDir() + '/data/repositories/' + args['name']
cmd = path + ' create ' + dest
data = public.execShell(cmd)
if data[1] == '':
public.execShell('chown -R csvn:csvn ' + dest)
return 'ok'
return 'fail'
def projectDel():
args = getArgs()
if not 'name' in args:
return 'project name missing'
dest = getServerDir() + '/data/repositories/' + args['name']
cmd = 'rm -rf ' + dest
data = public.execShell(cmd)
if data[0] == '':
return 'ok'
return 'fail'
def getHttpPort():
http_main_conf = getServerDir() + '/data/conf/csvn_main_httpd.conf'
try:
if os.path.exists(http_main_conf):
content = public.readFile(http_main_conf)
return re.search('Listen\s(\d+)', content).groups()[0]
except Exception as e:
pass # print e
return '80'
def getCsvnPort():
http_main_conf = getServerDir() + '/data/conf/csvn-wrapper.conf'
try:
if os.path.exists(http_main_conf):
content = public.readFile(http_main_conf)
return re.search('wrapper.java.additional.3=-Djetty.port=(\d+)', content).groups()[0]
except Exception as e:
pass # print e
return '3343'
def getALlProjectList(search=''):
path = getServerDir() + '/data/repositories'
dlist = []
if os.path.exists(path):
for filename in os.listdir(path):
tmp = {}
filePath = path + '/' + filename
if os.path.isdir(filePath):
if search == '':
tmp['name'] = filename
dlist.append(tmp)
else:
if filename.find(search) != -1:
tmp['name'] = filename
dlist.append(tmp)
return dlist
def checkProjectListIsHasScript(data):
dlen = len(data)
for x in range(dlen):
path = getServerDir() + '/data/repositories/' + \
data[x]['name'] + '/hooks/post-commit'
if os.path.exists(path):
data[x]['has_hook'] = True
else:
data[x]['has_hook'] = False
return data
def projectList():
import math
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
dlist = getALlProjectList(search)
dlist_sum = len(dlist)
start = (page - 1) * page_size
ret_data = dlist[start:start + page_size]
ret_data = checkProjectListIsHasScript(ret_data)
data = {}
data['data'] = ret_data
data['list'] = public.getPage(
{'count': dlist_sum, 'p': page, 'row': 10, 'tojs': 'csvnProjectList'})
data['ip'] = public.getLocalIp()
data['port'] = getHttpPort()
data['csvn_port'] = getCsvnPort()
return public.getJson(data)
def getAllAclList():
svn_access_file = getServerDir() + '/data/conf/svn_access_file'
aData = public.readFile(svn_access_file)
aData = re.sub('#.*', '', aData)
aData = aData.strip().split('[')[1:]
allAcl = {}
for i in range(len(aData)):
oData = aData[i].strip().split(']')
name = oData[0].strip('/').strip(':')
if oData[1] == '':
allAcl[name] = []
else:
user = oData[1].strip().split('\n')
userAll = []
for iu in range(len(user)):
ulist = user[iu].split('=')
utmp = {}
utmp['user'] = ulist[0].strip()
utmp['acl'] = ulist[1].strip()
userAll.append(utmp)
allAcl[name] = userAll
return allAcl
def makeAclFile(content):
# print content
svn_access_file = getServerDir() + '/data/conf/svn_access_file'
tmp = "\n"
for k, v in content.items():
if k == '':
tmp += "[/]\n"
else:
tmp += "[" + k + ":/]\n"
for iv in range(len(v)):
tmp += v[iv]['user'] + ' = ' + v[iv]['acl'] + "\n"
tmp += "\n"
# svn_tmp_path = getServerDir() + '/data/conf/svn_access_file.log'
return public.writeFile(svn_access_file, tmp)
def projectAclList():
args = getArgs()
if not 'name' in args:
return 'name missing!'
name = args['name']
acl = getAllAclList()
if name in acl:
return public.getJson(acl[name])
else:
return 'fail'
def projectAclAdd():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
uname = args['uname']
pname = args['pname']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
tmp_acl = {'user': uname, 'acl': 'rw'}
if not pname in acl:
acl[pname] = [tmp_acl]
makeAclFile(acl)
return 'ok'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
acl[pname] = [tmp_acl]
else:
is_have = False
for x in range(tmp_len):
if tmp[x]['user'] == uname:
is_have = True
return uname + ' users already exist!'
if not is_have:
tmp.append(tmp_acl)
acl[pname] = tmp
makeAclFile(acl)
return 'ok'
def projectAclDel():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
uname = args['uname']
pname = args['pname']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
if not pname in acl:
return 'project not exists!'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
return 'project no have user:' + uname
else:
is_have = False
rtmp = []
for x in range(tmp_len):
if tmp[x]['user'] != uname:
rtmp.append(tmp[x])
acl[pname] = rtmp
makeAclFile(acl)
return 'ok'
def projectAclSet():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
if not 'acl' in args:
return 'acl missing'
uname = args['uname']
pname = args['pname']
up_acl = args['acl']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
if not pname in acl:
return 'project not exists!'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
return 'project no have user:' + uname
else:
is_have = False
for x in range(tmp_len):
if tmp[x]['user'] == uname:
tmp[x]['acl'] = up_acl
acl[pname] = tmp
makeAclFile(acl)
return 'ok'
def getCsvnUser():
user = 'admin_sync'
acl = getAllAclList()
if '' in acl:
tmp = acl['']
is_has = False
for data in tmp:
if data['user'] == user:
is_has = True
if not is_has:
tmp.append({'user': user, 'acl': 'r'})
acl[''] = tmp
makeAclFile(acl)
return user
def getCsvnPwd(user):
if app_debug:
return user + '123'
pwd_file = 'data/csvn_sync.pl'
if os.path.exists(pwd_file):
return public.readFile(pwd_file).strip()
import time
cur_time = time.time()
rand_pwd = public.md5(str(cur_time))
pwd = user + rand_pwd[:5]
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -b ' + svn_auth_file + ' ' + user + ' ' + pwd
data = public.execShell(cmd)
public.writeFile(pwd_file, pwd)
return pwd
def projectScriptLoad():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
post_commit_tpl = getPluginDir() + '/hook/post-commit.tpl'
hook_path = getServerDir() + '/data/repositories/' + \
args['pname'] + '/hooks'
post_commit_file = hook_path + '/post-commit'
pct_content = public.readFile(post_commit_tpl)
public.writeFile(post_commit_file, pct_content)
public.execShell('chmod 777 ' + post_commit_file)
commit_tpl = getPluginDir() + '/hook/commit.tpl'
commit_file = hook_path + '/commit'
ct_content = public.readFile(commit_tpl)
ct_content = ct_content.replace('{$PROJECT_DIR}', public.getRootDir())
ct_content = ct_content.replace('{$PORT}', getHttpPort())
ct_content = ct_content.replace('{$CSVN_USER}', getCsvnUser())
ct_content = ct_content.replace('{$CSVN_PWD}', getCsvnPwd(getCsvnUser()))
public.writeFile(commit_file, ct_content)
public.execShell('chmod 777 ' + commit_file)
return 'ok'
def projectScriptUnload():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
post_commit_file = getServerDir() + '/data/repositories/' + '/' + \
args['pname'] + '/hooks/post-commit'
public.execShell('rm -f ' + post_commit_file)
commit_file = getServerDir() + '/data/repositories/' + '/' + \
args['pname'] + '/hooks/commit'
public.execShell('rm -f ' + commit_file)
return 'ok'
def projectScriptEdit():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
data = {}
commit_file = getServerDir() + '/data/repositories/' + \
args['pname'] + '/hooks/commit'
if os.path.exists(commit_file):
data['status'] = True
data['path'] = commit_file
else:
data['status'] = False
data['msg'] = 'file does not exist'
return public.getJson(data)
def projectScriptDebug():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
data = {}
commit_log = getServerDir() + '/data/repositories/' + \
args['pname'] + '/sh.log'
if os.path.exists(commit_log):
data['status'] = True
data['path'] = commit_log
else:
data['status'] = False
data['msg'] = 'file does not exist'
return public.getJson(data)
def getTotalStatistics():
st = status()
data = {}
if st == 'start':
svn_path = getServerDir() + '/data/repositories'
data['status'] = True
data['count'] = len(os.listdir(svn_path))
data['ver'] = public.readFile(getServerDir() + '/version.pl').strip()
return public.returnJson(True, 'ok', data)
else:
data['status'] = False
data['count'] = 0
return public.returnJson(False, 'fail', data)
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 == 'csvn_edit':
print csvnEdit()
elif func == 'user_list':
print userList()
elif func == 'user_add':
print userAdd()
elif func == 'user_del':
print userDel()
elif func == 'project_list':
print projectList()
elif func == 'project_del':
print projectDel()
elif func == 'project_add':
print projectAdd()
elif func == 'project_acl_list':
print projectAclList()
elif func == 'project_acl_add':
print projectAclAdd()
elif func == 'project_acl_del':
print projectAclDel()
elif func == 'project_acl_set':
print projectAclSet()
elif func == 'project_script_load':
print projectScriptLoad()
elif func == 'project_script_unload':
print projectScriptUnload()
elif func == 'project_script_edit':
print projectScriptEdit()
elif func == 'project_script_debug':
print projectScriptDebug()
elif func == 'get_total_statistics':
print getTotalStatistics()
else:
print 'fail'
+2 -2
View File
@@ -4,8 +4,8 @@
"shell": "install.sh",
"name": "csvn",
"title": "CSVN",
"versions": ["5.1"],
"updates":["5.1.4"],
"versions": "5.1",
"updates":"5.1.4",
"tip": "soft",
"checks": "server/csvn",
"author": "midoks",
+34 -5
View File
@@ -12,18 +12,47 @@ install_tmp=${rootPath}/tmp/bt_install.pl
CSVN_SOURCE='https://github.com/midoks/mdserver-web/releases/download/init/CollabNetSubversionEdge-5.1.4_linux-x86_64.tar.xz'
CheckJAVA()
{
which "java" > /dev/null
if [ $? -eq 0 ]
then
echo 'java is exist'
else
echo 'java install...'
yum install -y java
fi
}
Install_csvn()
{
mkdir -p $serverPath/tmp
CheckJAVA
mkdir -p $serverPath/source
echo '正在安装脚本文件...' > $install_tmp
if [ ! -f $serverPath/tmp/csvn.tar.xz ];then
wget -O $serverPath/so/csvn.tar.xz ${CSVN_SOURCE}
if [ ! -f $serverPath/source/csvn.tar.xz ];then
wget -O $serverPath/source/csvn.tar.xz ${CSVN_SOURCE}
fi
cd $serverPath/tmp && tar -Jxf $serverPath/tmp/csvn.tar.xz
mv $serverPath/tmp/csvn $serverPath/csvn
cd $serverPath/source && tar -Jxf $serverPath/source/csvn.tar.xz
mv $serverPath/source/csvn $serverPath/csvn
echo '5.1' > $serverPath/csvn/version.pl
if id -u csvn > /dev/null 2>&1; then
echo "csvn user exists"
else
useradd csvn
cp /etc/sudoers{,.`date +"%Y-%m-%d_%H-%M-%S"`}
echo "csvn ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
fi
chown -R csvn:csvn $serverPath/csvn
# $serverPath/csvn/bin/csvn install
# $serverPath/csvn/bin/csvn-httpd install
echo '安装完成' > $install_tmp
}
+500
View File
@@ -0,0 +1,500 @@
pluginService('csvn');
function csvnPost(method,args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:method, args:JSON.stringify(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 csvnEdit(){
csvnPost('csvn_edit',{} , function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
var edit = '<p class="status">通用的手动编辑:</p>';
edit +='<div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['svn_access_file']+'\');">权限编辑</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['post_commit_tpl']+'\');">post_commit_tpl</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['commit_tpl']+'\');">commit_tpl</button>\
</div>';
$(".soft-man-con").html(edit);
});
}
function csvnUserFind(){
var search = $('#csvn_find_user').val();
if (search==''){
layer.msg('搜索字符不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnUserList(1, search);
}
function csvnUserList(page, search) {
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
if(typeof(search) != 'undefined'){
_data['search'] = search;
}
csvnPost('user_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="csvn_find_user" style="height: 28px; border-radius: 3px;width: 505px;">';
content += '<button class="btn btn-success btn-sm" onclick="csvnUserFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>用户名</th>';
content += '<th>操作(<a class="btlink" onclick="csvnAddUser();">添加</a>)</th>';
content += '</tr></thead>';
content += '<tbody>';
ulist = rdata.data;
for (i in ulist){
content += '<tr><td>'+ulist[i]+'</td><td>'+
'<a class="btlink" onclick="csvnDelUser(\''+ulist[i]+'\')">删除</a> | ' +
'<a class="btlink" onclick="csvnModPwdUser(\''+ulist[i]+'\')">改密</a></td></tr>';
}
content += '</tbody>';
content += '</table></div>';
page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata.list;
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function csvnDelUser(name){
var loadOpen = layer.open({
type: 1,
title: '删除用户',
area: '350px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>你要确认要删除"+ name + "账户?</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_del_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_del_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_del_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_del_ok').click(function(){
_data = {};
_data['username'] = name;
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'user_del', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
}
layer.close(loadOpen);
layer.msg("删除成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnAddUser(username){
user_input = ''
if (typeof(username) == 'undefined'){
user_input = "<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入用户名'></div>";
} else {
user_input = "<div><input value='"+ username +"' class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 200px;' disabled='true'></div>";
}
var loadOpen = layer.open({
type: 1,
title: '添加用户',
area: '240px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>\
"+user_input+"\
<div style='padding-top:3px;'><input class='bt-input-text mr5 outline_no' type='text' id='csvn_password' name='password' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入密码'></div>\
</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_add_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_add_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_add_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_add_ok').click(function(){
_data = {};
_data['username'] = $('#csvn_username').val();
_data['password'] = $('#csvn_password').val();
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'user_add', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
}
csvnUserList();
layer.close(loadOpen);
layer.msg("操作成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnModPwdUser(name){
csvnAddUser(name);
}
function csvnProjectFind(){
var search = $('#csvn_project_find').val();
if (search == ''){
layer.msg('查找字符不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList(1, search);
}
function csvnProjectList(page, search){
var _data = {};
_data['page_size'] = 10;
if (typeof(search) != 'undefined'){
_data['search'] = search;
}
if (typeof(page) != 'undefined'){
_data['page'] = page;
setCookie('csvnProjectListPage',page);
} else {
_data['page'] = 1;
cookie_page = getCookie('csvnProjectListPage')
if (cookie_page >0){
_data['page'] = cookie_page;
}
}
csvnPost('project_list', _data, function(data){
var rdata = $.parseJSON($.trim(data.data));
var csvn_mg = project_url = 'http://' +rdata['ip'] +(rdata['csvn_port'] == '80' ? '': ':'+rdata['csvn_port']);
content = '<div><input class="bt-input-text mr5" type="text" placeholder="查找项目" id="csvn_project_find" style="height: 28px; border-radius: 3px;width: 505px;">';
content += '<button class="btn btn-success btn-sm" onclick="csvnProjectFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>项目名</th>';
content += '<th>地址</th>';
content += '<th>操作(<a class="btlink" onclick="csvnAddProject();">添加</a>) | <a class="btlink" target="_blank" href="'+csvn_mg+'">后台管理</a> </th>';
content += '</tr></thead>';
content += '<tbody>';
// console.log(rdata);
ulist = rdata.data;
for (i in ulist){
var project_url = 'http://' +rdata['ip'] +(rdata['port'] == '80' ? '': ':'+rdata['port'])+ '/svn/'+ulist[i]['name'];
var code_url = 'http://' +rdata['ip'] +(rdata['port'] == '80' ? '': ':'+rdata['port'])+ '/viewvc/'+ulist[i]['name'];
content += '<tr><td>'+ulist[i]['name']+'</td>'+
'<td>'+project_url+'</td><td>'+
'<a class="btlink" onclick="csvnDelProject(\''+ulist[i]['name']+'\')">删除</a> | ' +
'<a class="btlink" onclick="csvnAclProject(\''+ulist[i]['name']+'\')">权限</a> | ' +
'<a class="btlink" target="_blank" href="' + code_url +'">源码</a> | ' +
'<a class="btlink" onclick="csvnProjectScript(\''+ulist[i]['name']+'\','+ ulist[i]['has_hook']+')">脚本</a>' +
'</td></tr>';
}
content += '</tbody>';
content += '</table></div>';
page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata.list;
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function csvnDelProject(name){
var loadOpen = layer.open({
type: 1,
title: '删除用户',
area: '350px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>你要确认要删除"+ name + "账户?</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_del_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_del_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_del_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_del_ok').click(function(){
var _data = {};
_data['name'] = name;
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'project_del', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList();
layer.close(loadOpen);
layer.msg("删除成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnAddProject(){
var loadOpen = layer.open({
type: 1,
title: '添加项目',
area: '240px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>\
<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_name' name='username' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入项目名'></div>\
</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_project_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_project_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_project_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_project_ok').click(function(){
var _data = {};
_data['name'] = $('#csvn_name').val();
csvnPost('project_add', _data, function(data){
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList();
layer.close(loadOpen);
layer.msg("操作成功!",{icon:1,time:3000,shade: [0.3, '#000']});
});
});
}
function csvnProjectScript(pname, has_hook){
var html = '';
if (has_hook){
html += '<button onclick="csvnProjectScriptEdit(\''+pname+'\')" class="btn btn-default btn-sm">手动编辑</button>';
html += '<button onclick="csvnProjectScriptDebug(\''+pname+'\')" class="btn btn-default btn-sm">调试日志</button>';
html += '<button onclick="csvnProjectScriptLoad(\''+pname+'\')" class="btn btn-default btn-sm">重新加载</button>';
html += '<button onclick="csvnProjectScriptUnload(\''+pname+'\')" class="btn btn-default btn-sm">卸载脚本</button>';
} else {
html += '<button onclick="csvnProjectScriptLoad(\''+pname+'\')" class="btn btn-default btn-sm">加载脚本</button>';
}
var loadOpen = layer.open({
type: 1,
title: '脚本设置',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>'
});
}
function csvnProjectScriptLoad(pname){
csvnPost('project_script_load', {'pname':pname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
csvnProjectList();
},2000);
});
}
function csvnProjectScriptUnload(pname){
csvnPost('project_script_unload', {'pname':pname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
csvnProjectList();
},2000);
});
}
function csvnProjectScriptEdit(pname){
csvnPost('project_script_edit', {'pname':pname}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
csvnProjectList();
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function csvnProjectScriptDebug(pname){
csvnPost('project_script_debug', {'pname':pname}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
csvnProjectList();
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function csvnAclAdd(pname){
var uname = $('#csvn_username').val();
if (uname == ''){
layer.msg('添加用户名不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnPost('project_acl_add', {'pname':pname,'uname':uname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclDel(pname, uname){
csvnPost('project_acl_del', {'pname':pname,'uname':uname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclSet(obj, pname, uname, acl, selected){
if (selected){
$(obj).prop('checked',true);
layer.msg('权限没有变化!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnPost('project_acl_set', {'pname':pname,'uname':uname, 'acl':acl}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclProject(pname){
csvnPost('project_acl_list', {'name':pname}, function(data){
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e){}
var list = '';
for (i in rdata) {
var user = rdata[i]['user'];
var acl = '';
if (rdata[i]['acl'] == 'r'){
acl += '<input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'r\',true)" checked="true"> 只读 | <input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'rw\', false)"> 读写';
} else {
acl += '<input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'r\',false)"> 只读 | <input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'rw\',true)" checked="true"> 读写';
}
list += '<tr><td>'+user+'</td><td>' + acl +'</td>'+
'<td><a class="btlink" onclick="csvnAclDel(\''+pname+'\',\''+user+'\')">删除</a></td>'+'</tr>';
}
var loadOpen = layer.open({
type: 1,
title: '项目('+pname+')权限设置',
area: '300px',
content:"<div class='bt-form pd20 c6'>\
<div>\
<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 205px;' placeholder='用户名'>\
<button class='btn btn-success btn-sm' onclick='csvnAclAdd(\""+pname+"\");'>添加</button></div>\
<div class='divtable' style='margin-top:5px;'><table class='table table-hover'><thead><tr><th>用户</th><th>权限</th><th>操作</th></tr></thead>\
<tbody>"+list+"</tbody>\
</table></div>\
</div>\
</div>"
});
});
}
+7
View File
@@ -0,0 +1,7 @@
runtime: php55
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: helloworld.php
+3
View File
@@ -0,0 +1,3 @@
<?php
echo 'Hello, GAE!';
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

+27
View File
@@ -0,0 +1,27 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="readme();">插件说明</p>
<p onclick="projectList();">项目列表</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con">
</div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=gae&f=js/gae.js");
resetPluginWinWidth(720);
readme();
function readme(){
var html = '<p>开发文档:https://cloud.google.com/sdk/docs/</p>';
html += '<p>* 注意:本插件通过Google <a class="btlink" target="_blank" href="https://cloud.google.com/sdk/docs/scripting-gcloud">JSON 格式</a>赋权免交互式</p>';
html += '<p>* 注意:添加:gcloud auth activate-service-account --key-file [KEY_FILE]</p>';
html += '<p>* 注意:设置后,一般同步项目命令:gcloud app deploy << y</p>';
html += '<p>* 注意:可以查看命令,把命令加入到脚本中...自动更新。</p>';
$('.bt-w-main .soft-man-con').html(html);
}
</script>
+240
View File
@@ -0,0 +1,240 @@
# coding: utf-8
import time
import random
import os
import json
import re
import sys
sys.path.append(os.getcwd() + "/class/core")
import public
def getPluginName():
return 'gae'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def status():
return 'start'
def getAllProjectList(search):
path = public.getWwwDir()
dlist = []
if os.path.exists(path):
for filename in os.listdir(path):
tmp = {}
filePath = path + '/' + filename
if os.path.isdir(filePath):
if search == '':
tmp['name'] = filename
tmp['dir'] = filePath
dlist.append(tmp)
else:
if filename.find(search) != -1:
tmp['name'] = filename
tmp['dir'] = filePath
dlist.append(tmp)
return dlist
def checkProjectListIsSet(data):
dlen = len(data)
for x in range(dlen):
path = getServerDir() + '/' + data[x]['name'] + '.json'
if os.path.exists(path):
if os.path.getsize(path) == 0:
data[x]['isset'] = False
else:
data[x]['isset'] = True
else:
data[x]['isset'] = False
return data
def projectListEdit():
args = getArgs()
if not 'name' in args:
return 'missing name!'
file = getServerDir() + '/' + args['name'] + '.json'
if not os.path.exists(file):
public.execShell('touch ' + file)
return file
def projectListDel():
args = getArgs()
if not 'name' in args:
return 'missing name!'
file = getServerDir() + '/' + args['name'] + '.json'
if os.path.exists(file):
content = public.readFile(file)
contentObj = json.loads(content)
asyncUser = contentObj['client_email']
cmd = getServerDir() + '/google-cloud-sdk/bin/'
public.execShell(cmd + 'gcloud auth revoke ' + asyncUser)
public.execShell('rm -rf ' + file)
return 'ok'
def checkUserExist(cmd, user):
data = public.execShell(cmd + 'gcloud auth list | grep ' + user)
if data[0] == '':
return False
return True
def projectListAsync():
import subprocess
args = getArgs()
if not 'name' in args:
return 'missing name!'
file = getServerDir() + '/' + args['name'] + '.json'
if not os.path.exists(file):
return 'not configured file!'
content = public.readFile(file)
contentObj = json.loads(content)
asyncUser = contentObj['client_email']
cmd = getServerDir() + '/google-cloud-sdk/bin/'
projectDir = public.getWwwDir() + '/' + args['name']
if not checkUserExist(cmd, asyncUser):
public.execShell(
cmd + 'gcloud auth activate-service-account --key-file ' + file)
pName = contentObj['project_id']
setUserCmd = cmd + 'gcloud config set account ' + asyncUser
setUserCmd += ' && ' + cmd + 'gcloud config set project ' + pName
asyncCmd = setUserCmd + ' && cd ' + projectDir + \
' && ' + cmd + 'gcloud app deploy << y'
taskAdd = (None, 'gae[async]',
'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'), asyncCmd)
public.M('tasks').add('id,name,type,status,addtime, execstr', taskAdd)
return 'ok'
def projectListCmd():
args = getArgs()
if not 'name' in args:
return 'missing name!'
file = getServerDir() + '/' + args['name'] + '.json'
if not os.path.exists(file):
return 'not configured file!'
content = public.readFile(file)
contentObj = json.loads(content)
asyncUser = contentObj['client_email']
cmd = getServerDir() + '/google-cloud-sdk/bin/'
pName = contentObj['project_id']
projectDir = public.getWwwDir() + '/' + args['name']
setUserCmd = 'sudo ' + cmd + 'gcloud config set account ' + asyncUser
setUserCmd += ' && sudo ' + cmd + 'gcloud config set project ' + pName
asyncCmd = setUserCmd + ' && sudo cd ' + projectDir + \
' && sudo ' + cmd + 'gcloud app deploy <<y'
return asyncCmd
def projectListUrl():
args = getArgs()
if not 'name' in args:
return 'missing name!'
file = getServerDir() + '/' + args['name'] + '.json'
if not os.path.exists(file):
return 'not configured file!'
content = public.readFile(file)
contentObj = json.loads(content)
asyncUser = contentObj['client_email']
plist = asyncUser.split('@')
url = 'https://' + plist[0] + '.appspot.com'
return url
def projectList():
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
dlist = getAllProjectList(search)
dlist_sum = len(dlist)
start = (page - 1) * page_size
ret_data = dlist[start:start + page_size]
ret_data = checkProjectListIsSet(ret_data)
data = {}
data['data'] = ret_data
data['list'] = public.getPage(
{'count': dlist_sum, 'p': page, 'row': 10, 'tojs': 'projectList'})
return public.getJson(data)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print status()
elif func == 'project_list':
print projectList()
elif func == 'project_list_edit':
print projectListEdit()
elif func == 'project_list_del':
print projectListDel()
elif func == 'project_list_async':
print projectListAsync()
elif func == 'project_list_cmd':
print projectListCmd()
elif func == 'project_list_url':
print projectListUrl()
else:
print 'error'
+14
View File
@@ -0,0 +1,14 @@
{
"title":"GAE",
"tip":"soft",
"name":"gae",
"ps":"GAE(Google App Engine)。它是Google管理的数据中心中用于WEB应用程序的开发和托管的平台",
"versions": "0.1",
"shell":"install.sh",
"checks":"server/gae",
"path":"server/gae",
"author":"mdserver-web",
"home":"https://github.com/midoks/mdserver-web",
"date":"2018-11-30",
"pid":"5"
}
+51
View File
@@ -0,0 +1,51 @@
#!/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/bt_install.pl
Install_gae()
{
mkdir -p ${serverPath}/gae
mkdir -p ${serverPath}/source/gae
os=`uname`
if [ "Darwin" == "$os" ];then
file=google-cloud-sdk-218.0.0-darwin-x86_64.tar.gz
else
file=google-cloud-sdk-218.0.0-linux-x86_64.tar.gz
fi
if [ ! -f $serverPath/source/gae/$file ];then
wget -O $serverPath/source/gae/$file https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/$file
fi
if [ ! -d $serverPath/source/gae/google-cloud-sdk ];then
cd $serverPath/source/gae && tar zxvf $file
fi
cp -r $serverPath/source/gae/google-cloud-sdk ${serverPath}/gae
echo "${1}" > ${serverPath}/gae/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_gae()
{
rm -rf ${serverPath}/gae
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_gae $2
else
Uninstall_gae $2
fi
+164
View File
@@ -0,0 +1,164 @@
function gaePost(method,args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'gae', func:method, args:JSON.stringify(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 projectList(page, search){
var _data = {};
_data['page_size'] = 10;
if (typeof(search) != 'undefined'){
_data['search'] = search;
}
if (typeof(page) != 'undefined'){
_data['page'] = page;
setCookie('gaeProjectListPage',page);
} else {
_data['page'] = 1;
cookie_page = getCookie('gaeProjectListPage')
if (cookie_page >0){
_data['page'] = cookie_page;
}
}
gaePost('project_list', _data, function(data){
var rdata = $.parseJSON($.trim(data.data));
// console.log(rdata);
content = '<div><input class="bt-input-text mr5" type="text" placeholder="查找项目" id="project_find" style="height: 28px; border-radius: 3px;width: 435px;">';
content += '<button class="btn btn-success btn-sm" onclick="projectListFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>项目名</th>';
content += '<th>地址</th>';
content += '<th>操作(<a class="btlink" target="_blank" href="https://console.cloud.google.com/">官方地址</a>)</th>';
content += '</tr></thead>';
content += '<tbody>';
ulist = rdata.data;
for (i in ulist){
setName = ulist[i]['isset'] ? '已设置' : '设置';
content += '<tr><td>'+ulist[i]['name']+'</td>'+
'<td>'+ulist[i]['dir']+'</td><td>'+
'<a class="btlink" onclick="gaeSetProject(\''+ulist[i]['name']+'\','+ulist[i]['isset']+')">'+setName+'</a> | ' +
'<a class="btlink" onclick="gaeAsyncProject(\''+ulist[i]['name']+'\')">同步</a> | ' +
'<a class="btlink" target="_blank" onclick="gaeProjectCmd(\''+ulist[i]['name']+'\')">命令</a> | ' +
'<a class="btlink" target="_blank" onclick="gaeProjectUrl(\''+ulist[i]['name']+'\')">访问</a>' +
'</td></tr>';
}
content += '</tbody>';
content += '</table></div>';
page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata.list;
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function projectListFind(){
var search = $('#project_find').val();
if (search == ''){
layer.msg('查找字符不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
projectList(1, search);
}
function gaeSetProject(pname,isset){
var html = '';
if (isset){
html += '<button onclick="gaeProjectDel(\''+pname+'\')" class="btn btn-default btn-sm">删除</button>';
}
html += '<button onclick="gaeProjectEdit(\''+pname+'\')" class="btn btn-default btn-sm">编辑</button>';
var loadOpen = layer.open({
type: 1,
title: '['+ pname +']密钥设置',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>'
});
}
function gaeProjectEdit(pname){
gaePost('project_list_edit', {'name':pname}, function(data){
onlineEditFile(0,data.data);
});
}
function gaeProjectDel(pname){
gaePost('project_list_del', {'name':pname}, function(data){
showMsg('删除成功!',function(){
$('.layui-layer-close1').click();
projectList();
},{icon:0,time:2000,shade: [0.3, '#000']});
});
}
function gaeAsyncProject(pname){
gaePost('project_list_async', {'name':pname}, function(data){
if (data.data !='ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
} else {
layer.msg('加入任务,请自行观察!',{icon:1,time:2000,shade: [0.3, '#000']});
}
$('.layui-layer-close1').click();
});
}
function stringToEntity(str,radix){
let arr=[]
//返回的字符实体默认10进制,也可以选择16进制
radix=radix||0
for(let i=0;i<str.length;i++){
arr.push((!radix?'&#'+str.charCodeAt(i):'&#x'+str.charCodeAt(i).toString(16))+';')
}
let tmp=arr.join('')
// console.log(`'${str}' 转实体为 '${tmp}'`)
return tmp
}
function gaeProjectCmd(pname){
gaePost('project_list_cmd', {'name':pname}, function(data){
var data_str = data.data;
if (data_str.indexOf('gcloud') !== -1){
layer.msg(stringToEntity(data.data),{icon:1,time:5000,shade: [0.3, '#000']});
} else {
layer.msg(data.data,{icon:0,time:5000,shade: [0.3, '#000']});
}
});
}
function gaeProjectUrl(pname){
gaePost('project_list_url', {'name':pname}, function(data){
var data_str = data.data;
if (data_str.indexOf('appspot.com') !== -1){
window.open(data.data);
} else {
layer.msg(data.data,{icon:0,time:5000,shade: [0.3, '#000']});
}
});
}
+91
View File
@@ -0,0 +1,91 @@
# coding: utf-8
import re
import os
import sys
sys.path.append("/usr/local/lib/python2.7/site-packages")
class mysql:
__DB_PASS = None
__DB_USER = 'root'
__DB_PORT = 3306
__DB_HOST = 'localhost'
__DB_NAME = 'test'
__DB_CONN = None
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
def __Conn(self):
'''连接MYSQL数据库'''
try:
socket = '/tmp/mysql.sock'
try:
import MySQLdb
except Exception, ex:
self.__DB_ERR = ex
return False
try:
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=self.__DB_PORT, db=self.__DB_NAME, charset="utf8", connect_timeout=10, unix_socket=socket)
except MySQLdb.Error, e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=self.__DB_PORT, db=self.__DB_NAME, charset="utf8", connect_timeout=10, unix_socket=socket)
self.__DB_CUR = self.__DB_CONN.cursor()
return True
except MySQLdb.Error, e:
self.__DB_ERR = e
return False
def setHost(self, host):
self.__DB_HOST = host
def setPwd(self, pwd):
self.__DB_PASS = pwd
def setUser(self, user):
self.__DB_USER = user
def setPort(self, port):
self.__DB_PORT = port
def setDb(self, name):
self.__DB_NAME = name
def getPwd(self):
return self.__DB_PASS
def execute(self, sql):
# 执行SQL语句返回受影响行
if not self.__Conn():
return self.__DB_ERR
try:
result = self.__DB_CUR.execute(sql)
self.__DB_CONN.commit()
self.__Close()
return result
except Exception, ex:
return ex
def query(self, sql):
# 执行SQL语句返回数据集
if not self.__Conn():
return self.__DB_ERR
try:
self.__DB_CUR.execute(sql)
result = self.__DB_CUR.fetchall()
# 将元组转换成列表
data = map(list, result)
self.__Close()
return data
except Exception, ex:
return ex
# 关闭连接
def __Close(self):
self.__DB_CUR.close()
self.__DB_CONN.close()
+63
View File
@@ -0,0 +1,63 @@
APP_NAME = Gogs
RUN_USER = {$RUN_USER}
RUN_MODE = prod
[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gogs
USER = gogs
PASSWD = gogs
SSL_MODE = disable
PATH = data/gogs.db
[repository]
ROOT = {$ROOT_PATH}/gogs-repositories
FORCE_PRIVATE = false
[server]
DOMAIN = 127.0.0.1
HTTP_PORT = 3000
ROOT_URL = http://127.0.0.1:3000/
DISABLE_SSH = false
SSH_PORT = 2000
START_SSH_SERVER = false
OFFLINE_MODE = false
LANDING_PAGE = home
[mailer]
ENABLED = false
HOST = smtp.163.com:465
USER = midoks@163.com
PASSWD = ***
USE_PLAIN_TEXT = true
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = false
ENABLE_CAPTCHA = true
REQUIRE_SIGNIN_VIEW = false
[picture]
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = false
[session]
PROVIDER = file
[log]
MODE = console, file
LEVEL = Info
ROOT_PATH = {$SERVER_PATH}/gogs/log
[security]
INSTALL_LOCK = true
SECRET_KEY = jmGSJXDBH5Ng4wt
[other]
SHOW_FOOTER_BRANDING = false
SHOW_FOOTER_VERSION = false
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
GITADDR="{$GITROOTURL}{$USERNAME}/{$PROJECT}"
GIT_SDIR="{$CODE_DIR}"
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
# echo $GIT_PROJECT_DIR
if [ ! -d $GIT_PROJECT_DIR ];then
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
git clone $GITADDR
fi
unset GIT_DIR
cd $GIT_PROJECT_DIR && git pull
# func 2
# cd $GIT_PROJECT_DIR && env -i git pull origin master
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
mkdir -p $WEB_PATH
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
sysName=`uname`
if [ $sysName == 'Darwin' ]; then
USER=$(who | sed -n "2,1p" |awk '{print $1}')
chown -R $USER:staff $WEB_PATH
else
chown -R www:www $WEB_PATH
fi
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
sh -x {$PATH}/commit 2>{$PATH}/sh.log
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+23
View File
@@ -0,0 +1,23 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('gogs');">服务</p>
<p onclick="pluginInitD('gogs');">自启动</p>
<p onclick="pluginConfig('gogs',null, 'init_conf');">启动配置</p>
<p onclick="gogsEdit();">手动编辑</p>
<p onclick="pluginConfig('gogs',null, 'conf');">配置文件</p>
<p onclick="gogsSetConfig();">配置修改</p>
<p onclick="gogsUserList();">用户列表</p>
<p onclick="pluginLogs('gogs',null,'run_log');">运行日志</p>
<p onclick="pluginLogs('gogs',null,'post_receive_log');" title="提交post-receive日志">提交日志</p>
<p onclick="gogsRead();">使用说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=gogs&f=js/gogs.js");
pluginService('gogs');
</script>
+641
View File
@@ -0,0 +1,641 @@
# coding: utf-8
import time
import os
import sys
import re
sys.path.append("/usr/local/lib/python2.7/site-packages")
import psutil
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.getOs() == 'darwin':
app_debug = True
def getPluginName():
return 'gogs'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
sys.path.append(getPluginDir() + "/class")
import mysql
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def getInitdConfTpl():
path = getPluginDir() + "/init.d/gogs.tpl"
return path
def getInitdConf():
path = getServerDir() + "/init.d/gogs"
return path
def getConf():
path = getServerDir() + "/custom/conf/app.ini"
return path
def getConfTpl():
path = getPluginDir() + "/conf/app.ini"
return path
def status():
data = public.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def contentReplace(content):
user = 'root'
if public.isAppleSystem():
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
content = content.replace('{$HOME_DIR}', '/Users/' + user)
else:
content = content.replace('{$HOME_DIR}', '/root')
service_path = public.getServerDir()
content = content.replace('{$ROOT_PATH}', public.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$RUN_USER}', user)
return content
def initDreplace():
file_tpl = getInitdConfTpl()
service_path = public.getServerDir()
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
if not os.path.exists(file_bin):
content = public.readFile(file_tpl)
content = contentReplace(content)
public.writeFile(file_bin, content)
public.execShell('chmod +x ' + file_bin)
conf_bin = getConf()
if not os.path.exists(conf_bin):
public.execShell('mkdir -p ' + getServerDir() + '/custom/conf')
conf_tpl = getConfTpl()
content = public.readFile(conf_tpl)
content = contentReplace(content)
public.writeFile(conf_bin, content)
log_path = getServerDir() + '/log'
if not os.path.exists(log_path):
os.mkdir(log_path)
return file_bin
def getRootUrl():
content = public.readFile(getConf())
rep = 'ROOT_URL\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
return tmp.groups()[0]
def getRootPath():
content = public.readFile(getConf())
rep = 'ROOT\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
return tmp.groups()[0]
def getDbConfValue():
content = public.readFile(getConf())
rep_scope = "\[database\](.*?)\["
tmp = re.findall(rep_scope, content, re.S)
rep = '(\w*)\s*=\s*(.*)'
tmp = re.findall(rep, tmp[0])
r = {}
for x in range(len(tmp)):
k = tmp[x][0]
v = tmp[x][1]
r[k] = v
return r
def pMysqlDb():
conf = getDbConfValue()
host = conf['HOST'].split(':')
conn = mysql.mysql()
conn.setHost(host[0])
conn.setUser(conf['USER'])
conn.setPwd(conf['PASSWD'])
conn.setPort(int(host[1]))
conn.setDb(conf['NAME'])
return conn
def isSqlError(mysqlMsg):
# 检测数据库执行错误
_mysqlMsg = str(mysqlMsg)
# print _mysqlMsg
if "MySQLdb" in _mysqlMsg:
return public.returnData(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python')
if "2002," in _mysqlMsg:
return public.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
if "using password:" in _mysqlMsg:
return public.returnData(False, '数据库管理密码错误!')
if "Connection refused" in _mysqlMsg:
return public.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
if "1133," in _mysqlMsg:
return public.returnData(False, '数据库用户不存在!')
if "1007," in _mysqlMsg:
return public.returnData(False, '数据库已经存在!')
if "1044," in _mysqlMsg:
return public.returnData(False, mysqlMsg[1])
if "2003," in _mysqlMsg:
return public.returnData(False, mysqlMsg[1])
return public.returnData(True, 'OK')
def start():
is_frist = True
conf_bin = getConf()
if os.path.exists(conf_bin):
is_frist = False
file = initDreplace()
if is_frist:
return "第一次启动Gogs,默认使用MySQL连接!<br>可以在配置文件中重新设置,再启动!"
conn = pMysqlDb()
list_table = conn.query('show tables')
data = isSqlError(list_table)
if not data['status']:
return data['msg']
data = public.execShell(file + ' start')
if data[1] == '':
return 'ok'
return data[0]
def stop():
file = initDreplace()
data = public.execShell(file + ' stop')
if data[1] == '':
return 'ok'
return data[1]
def restart():
file = initDreplace()
data = public.execShell(file + ' reload')
if data[1] == '':
return 'ok'
return data[1]
def reload():
file = initDreplace()
data = public.execShell(file + ' reload')
if data[1] == '':
return 'ok'
return data[1]
def initdStatus():
if not app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
mem_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(mem_bin, initd_bin)
public.execShell('chmod +x ' + initd_bin)
return 'ok'
def initdUinstall():
if not app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
initd_bin = getInitDFile()
os.remove(initd_bin)
return 'ok'
def runLog():
log_path = getServerDir() + '/log/gogs.log'
return log_path
def postReceiveLog():
log_path = getServerDir() + '/log/hooks/post-receive.log'
return log_path
def getGogsConf():
gets = [
{'name': 'DOMAIN', 'type': -1, 'ps': '服务器域名'},
{'name': 'ROOT_URL', 'type': -1, 'ps': '公开的完整URL路径'},
{'name': 'HTTP_ADDR', 'type': -1, 'ps': '应用HTTP监听地址'},
{'name': 'HTTP_PORT', 'type': -1, 'ps': '应用 HTTP 监听端口号'},
{'name': 'START_SSH_SERVER', 'type': 2, 'ps': '启动内置SSH服务器'},
{'name': 'SSH_PORT', 'type': -1, 'ps': 'SSH 端口号'},
{'name': 'REQUIRE_SIGNIN_VIEW', 'type': 2, 'ps': '强制登录浏览'},
{'name': 'ENABLE_CAPTCHA', 'type': 2, 'ps': '启用验证码服务'},
{'name': 'DISABLE_REGISTRATION', 'type': 2, 'ps': '禁止注册,只能由管理员创建帐号'},
{'name': 'ENABLE_NOTIFY_MAIL', 'type': 2, 'ps': '是否开启邮件通知'},
{'name': 'FORCE_PRIVATE', 'type': 2, 'ps': '强制要求所有新建的仓库都是私有'},
{'name': 'SHOW_FOOTER_BRANDING', 'type': 2, 'ps': 'Gogs推广信息'},
{'name': 'SHOW_FOOTER_VERSION', 'type': 2, 'ps': 'Gogs版本信息'},
{'name': 'SHOW_FOOTER_TEMPLATE_LOAD_TIME', 'type': 2, 'ps': 'Gogs模板加载时间'},
]
conf = public.readFile(getConf())
result = []
for g in gets:
rep = g['name'] + '\s*=\s*(.*)'
tmp = re.search(rep, conf)
if not tmp:
continue
g['value'] = tmp.groups()[0]
result.append(g)
return public.getJson(result)
def submitGogsConf():
gets = ['DOMAIN',
'ROOT_URL',
'HTTP_ADDR',
'HTTP_PORT',
'START_SSH_SERVER',
'SSH_PORT',
'REQUIRE_SIGNIN_VIEW',
'FORCE_PRIVATE',
'ENABLE_CAPTCHA',
'DISABLE_REGISTRATION',
'ENABLE_NOTIFY_MAIL',
'SHOW_FOOTER_BRANDING',
'SHOW_FOOTER_VERSION',
'SHOW_FOOTER_TEMPLATE_LOAD_TIME']
args = getArgs()
filename = getConf()
conf = public.readFile(filename)
for g in gets:
if g in args:
rep = g + '\s*=\s*(.*)'
val = g + ' = ' + args[g]
conf = re.sub(rep, val, conf)
public.writeFile(filename, conf)
reload()
return public.returnJson(True, '设置成功')
def userList():
import math
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
data = {}
data['root_url'] = getRootUrl()
pm = pMysqlDb()
start = (page - 1) * page_size
list_count = pm.query('select count(id) as num from user')
count = list_count[0][0]
list_data = pm.query(
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
page_info = {'count': count, 'p': page,
'row': page_size, 'tojs': 'gogsUserList'}
data['list'] = public.getPage(page_info)
data['page'] = page
data['page_size'] = page_size
data['page_count'] = int(math.ceil(count / page_size))
data['data'] = list_data
return public.returnJson(True, 'OK', data)
def getAllUserProject(user, search=''):
path = getRootPath() + '/' + user
dlist = []
if os.path.exists(path):
for filename in os.listdir(path):
tmp = {}
filePath = path + '/' + filename
if os.path.isdir(filePath):
if search == '':
tmp['name'] = filename.replace('.git', '')
dlist.append(tmp)
else:
if filename.find(search) != -1:
tmp['name'] = filename.replace('.git', '')
dlist.append(tmp)
return dlist
def checkProjectListIsHasScript(user, data):
path = getRootPath() + '/' + user
for x in range(len(data)):
name = data[x]['name'] + '.git'
path_tmp = path + '/' + name + '/custom_hooks/post-receive'
if os.path.exists(path_tmp):
data[x]['has_hook'] = True
else:
data[x]['has_hook'] = False
return data
def userProjectList():
import math
args = getArgs()
# print args
page = 1
page_size = 5
search = ''
if not 'name' in args:
return public.returnJson(False, '缺少参数name')
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
data = {}
ulist = getAllUserProject(args['name'])
dlist_sum = len(ulist)
start = (page - 1) * page_size
ret_data = ulist[start:start + page_size]
ret_data = checkProjectListIsHasScript(args['name'], ret_data)
data['root_url'] = getRootUrl()
data['data'] = ret_data
data['args'] = args
data['list'] = public.getPage(
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectList'})
return public.returnJson(True, 'OK', data)
def projectScriptEdit():
args = getArgs()
if not 'user' in args:
return public.returnJson(True, 'username missing')
if not 'name' in args:
return public.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
post_receive = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/post-receive'
if os.path.exists(post_receive):
return public.returnJson(True, 'OK', {'path': post_receive})
else:
return public.returnJson(False, 'file does not exist')
def projectScriptLoad():
args = getArgs()
if not 'user' in args:
return public.returnJson(True, 'username missing')
if not 'name' in args:
return public.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
path = getRootPath() + '/' + user + '/' + name
post_receive_tpl = getPluginDir() + '/hook/post-receive.tpl'
post_receive = path + '/custom_hooks/post-receive'
if not os.path.exists(path + '/custom_hooks'):
public.execShell('mkdir -p ' + path + '/custom_hooks')
pct_content = public.readFile(post_receive_tpl)
pct_content = pct_content.replace('{$PATH}', path + '/custom_hooks')
public.writeFile(post_receive, pct_content)
public.execShell('chmod 777 ' + post_receive)
commit_tpl = getPluginDir() + '/hook/commit.tpl'
commit = path + '/custom_hooks/commit'
codeDir = public.getRootDir() + '/git'
cc_content = public.readFile(commit_tpl)
cc_content = cc_content.replace('{$GITROOTURL}', getRootUrl())
cc_content = cc_content.replace('{$CODE_DIR}', codeDir)
cc_content = cc_content.replace('{$USERNAME}', user)
cc_content = cc_content.replace('{$PROJECT}', args['name'])
cc_content = cc_content.replace('{$WEB_ROOT}', public.getWwwDir())
public.writeFile(commit, cc_content)
public.execShell('chmod 777 ' + commit)
return 'ok'
def projectScriptUnload():
args = getArgs()
if not 'user' in args:
return public.returnJson(True, 'username missing')
if not 'name' in args:
return public.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
post_receive = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/post-receive'
public.execShell('rm -f ' + post_receive)
commit = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/commit'
public.execShell('rm -f ' + commit)
return 'ok'
def projectScriptDebug():
args = getArgs()
if not 'user' in args:
return public.returnJson(True, 'username missing')
if not 'name' in args:
return public.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
commit_log = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/sh.log'
data = {}
if os.path.exists(commit_log):
data['status'] = True
data['path'] = commit_log
else:
data['status'] = False
data['msg'] = '没有日志文件'
return public.getJson(data)
def gogsEdit():
data = {}
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
data['commit'] = getPluginDir() + '/hook/commit.tpl'
return public.getJson(data)
def getTotalStatistics():
st = status()
data = {}
if st == 'start':
pm = pMysqlDb()
list_count = pm.query('select count(id) as num from repository')
count = list_count[0][0]
data['status'] = True
data['count'] = count
data['ver'] = public.readFile(getServerDir() + '/version.pl').strip()
return public.returnJson(True, 'ok', data)
else:
data['status'] = False
data['count'] = 0
return public.returnJson(False, 'fail', data)
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 == 'run_log':
print runLog()
elif func == 'post_receive_log':
print postReceiveLog()
elif func == 'conf':
print getConf()
elif func == 'init_conf':
print getInitdConf()
elif func == 'get_gogs_conf':
print getGogsConf()
elif func == 'submit_gogs_conf':
print submitGogsConf()
elif func == 'user_list':
print userList()
elif func == 'user_project_list':
print userProjectList()
elif func == 'project_script_edit':
print projectScriptEdit()
elif func == 'project_script_load':
print projectScriptLoad()
elif func == 'project_script_unload':
print projectScriptUnload()
elif func == 'project_script_debug':
print projectScriptDebug()
elif func == 'gogs_edit':
print gogsEdit()
elif func == 'get_total_statistics':
print getTotalStatistics()
else:
print 'fail'
+15
View File
@@ -0,0 +1,15 @@
{
"ps": "Gogs是一款极易搭建的自助Git服务",
"name": "gogs",
"title": "Gogs",
"versions": ["0.11.86","0.11.79"],
"tip": "soft",
"checks": "server/gogs",
"author": "midoks",
"date": "201-04-01",
"home": "https://gogs.io",
"type": "git服务器",
"shell": "install.sh",
"pid": "3",
"sort": 7
}
+101
View File
@@ -0,0 +1,101 @@
#!/bin/sh
#
# /etc/rc.d/init.d/gogs
#
# Runs the Gogs
#
#
# chkconfig: - 85 15
#
### BEGIN INIT INFO
# Provides: gogs
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Should-Start: mysql postgresql
# Should-Stop: mysql postgresql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start gogs at boot time.
# Description: Control gogs.
### END INIT INFO
# Source function library.
if [ -f /etc/init.d/functions ];then
. /etc/init.d/functions
fi
# Default values
HOME={$HOME_DIR}
NAME=gogs
GOGS_HOME={$SERVER_PATH}/gogs
GOGS_PATH=${GOGS_HOME}/$NAME
GOGS_USER=midoks
SERVICENAME="Gogs"
LOCKFILE=/tmp/gogs.lock
LOGPATH=${GOGS_HOME}/log
LOGFILE=${LOGPATH}/gogs.log
RETVAL=0
status(){
isStart=`ps -ef|grep 'gogs web' |grep -v grep|awk '{print $2}'`
if [ "$isStart" == '' ];then
echo "${SERVICENAME} not running"
else
echo "${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
start() {
isStart=`ps -ef|grep 'gogs web' |grep -v grep|awk '{print $2}'`
if [ "$isStart" != '' ];then
echo "${SERVICENAME}(pid $(echo $isStart)) already running"
return $RETVAL
fi
cd ${GOGS_HOME}
echo "Starting ${SERVICENAME}: \c"
${GOGS_PATH} web > ${LOGFILE} 2>&1 &
RETVAL=$?
[ $RETVAL = 0 ] && touch ${LOCKFILE} && echo "\033[32mdone\033[0m"
return $RETVAL
}
stop() {
cd ${GOGS_HOME}
echo "Shutting down ${SERVICENAME}: \c"
which "killproc" > /dev/null
if [ $? -eq 0 ];then
killproc ${NAME}
else
pkill ${NAME}
fi
RETVAL=$?
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} && echo "\033[32mdone\033[0m"
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
reload)
stop
start
;;
*)
echo "Usage: ${NAME} {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
+68
View File
@@ -0,0 +1,68 @@
#!/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/bt_install.pl
GOGS_DOWNLOAD='https://dl.gogs.io'
getOs(){
os=`uname`
if [ "Darwin" == "$os" ];then
echo 'darwin'
else
echo 'linux'
fi
return 0
}
getBit(){
echo `getconf LONG_BIT`
}
Install_gogs()
{
mkdir -p $serverPath/source/gogs
echo '正在安装脚本文件...' > $install_tmp
version=$1
os=`getOs`
if [ "darwin" == "$os" ];then
file=gogs_${version}_darwin_amd64.zip
else
file=gogs_${version}_linux_amd64.zip
fi
if [ ! -f $serverPath/source/gogs/$file ];then
wget -O $serverPath/source/gogs/$file ${GOGS_DOWNLOAD}/${version}/${file}
fi
cd $serverPath/source/gogs && unzip -o $file -d gogs_${version}
mv $serverPath/source/gogs/gogs_${version}/gogs/ $serverPath/gogs
echo $version > $serverPath/gogs/version.pl
echo 'install success' > $install_tmp
}
Uninstall_gogs()
{
rm -rf $serverPath/gogs
echo 'uninstall success' > $install_tmp
}
action=$1
version=$2
if [ "${1}" == 'install' ];then
Install_gogs $version
else
Uninstall_gogs $version
fi
+320
View File
@@ -0,0 +1,320 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function gogsPost(method,args,callback, title){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(str2Obj(args));
} else {
_args = JSON.stringify(args);
}
var _title = '正在获取...';
if (typeof(title) != 'undefined'){
_title = title;
}
var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'gogs', 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 gogsSetConfig(){
gogsPost('get_gogs_conf', '', function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var mlist = '';
for (var i = 0; i < rdata.length; i++) {
var w = '140';
if (rdata[i].name == 'error_reporting') w = '250';
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
switch (rdata[i].type) {
case 0:
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="1" ' + selected_1 + '>开启</option>\
<option value="0" ' + selected_0 + '>关闭</option>\
</select>';
break;
case 1:
var selected_1 = (rdata[i].value == 'On') ? 'selected' : '';
var selected_0 = (rdata[i].value == 'Off') ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="On" ' + selected_1 + '>开启</option>\
<option value="Off" ' + selected_0 + '>关闭</option></select>'
break;
case 2:
var selected_1 = (rdata[i].value == 'true') ? 'selected' : '';
var selected_0 = (rdata[i].value == 'false') ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="true" ' + selected_1 + '>开启</option>\
<option value="false" ' + selected_0 + '>关闭</option></select>'
break;
}
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
}
var html = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm mr5" onclick="gogsSetConfig()">刷新</button>\
<button class="btn btn-success btn-sm" onclick="submitGogsConf()">保存</button></div>\
</div>';
$(".soft-man-con").html(html);
});
}
//提交PHP配置
function submitGogsConf() {
var data = {
DOMAIN: $("select[name='DOMAIN']").val(),
ROOT_URL: $("select[name='ROOT_URL']").val(),
HTTP_ADDR: $("select[name='HTTP_ADDR']").val(),
HTTP_PORT: $("select[name='HTTP_PORT']").val(),
START_SSH_SERVER: $("select[name='START_SSH_SERVER']").val() || 'false',
SSH_PORT: $("select[name='SSH_PORT']").val(),
ROOT_URL: $("select[name='ROOT_URL']").val(),
REQUIRE_SIGNIN_VIEW: $("select[name='REQUIRE_SIGNIN_VIEW']").val() || 'false',
ENABLE_CAPTCHA: $("select[name='ENABLE_CAPTCHA']").val() || 'true',
DISABLE_REGISTRATION: $("select[name='DISABLE_REGISTRATION']").val() || 'false',
ENABLE_NOTIFY_MAIL: $("select[name='ENABLE_NOTIFY_MAIL']").val() || 'false',
FORCE_PRIVATE: $("select[name='FORCE_PRIVATE']").val() || 'false',
SHOW_FOOTER_BRANDING: $("select[name='SHOW_FOOTER_BRANDING']").val() || 'false',
SHOW_FOOTER_VERSION: $("select[name='SHOW_FOOTER_VERSION']").val() || 'false',
SHOW_FOOTER_TEMPLATE_LOAD_TIME: $("select[name='SHOW_FOOTER_TEMPLATE_LOAD_TIME']").val() || 'false',
};
gogsPost('submit_gogs_conf', data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
gogsSetConfig();
});
}
function gogsEdit(){
gogsPost('gogs_edit',{} , function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
var edit = '<p class="status">通用的手动编辑:</p>';
edit +='<div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['post_receive']+'\');">post-receive.tpl</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['commit']+'\');">commit.tpl</button>\
</div>';
$(".soft-man-con").html(edit);
});
}
function gogsUserList(page, search) {
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
if(typeof(search) != 'undefined'){
_data['search'] = search;
}
gogsPost('user_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="find_user" style="height: 28px; border-radius: 3px;width: 435px;">';
content += '<button class="btn btn-success btn-sm" onclick="userFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>序号</th>';
content += '<th>用户或组织</th>';
content += '<th>邮件地址</th>';
content += '<th>操作(<a href="'+rdata['data']['root_url']+'" class="btlink" target="_blank">WEB管理</a>)</th>';
content += '</tr></thead>';
content += '<tbody>';
ulist = rdata['data']['data'];
for (i in ulist){
email = ulist[i][2] == '' ? '无' : ulist[i][2];
content += '<tr><td>'+ulist[i][0]+'</td>'+
'<td>'+ulist[i][1]+'</td>'+
'<td>'+email+'</td>'+
'<td><a class="btlink" onclick="userProjectList(\''+ulist[i][1]+'\')">项目管理</a></td>'+
'</tr>';
}
content += '</tbody>';
content += '</table></div>';
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata['data']['list'];
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function userProjectList(user, search){
var req = {};
if (!isNaN(user)){
req['page'] = user;
req['name'] = user = getCookie('gogsUserSelected');
} else {
req['page'] = 1;
req['name'] = user;
setCookie('gogsUserSelected', user);
}
req['page_size'] = 5;
req['search'] = '';
if(typeof(search) != 'undefined'){
req['search'] = search;
}
$('.layui-layer-close1').click();
gogsPost('user_project_list', req, function(data){
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e){}
if (!rdata['status']){
layer.msg(rdata['msg'], { icon: 2 });
return;
}
var list = '';
// console.log(rdata);
var project_list = rdata['data']['data'];
for (i in project_list) {
var name = project_list[i]['name'];
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>\
</td>\
</tr>';
}
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata['data']['list'];
page += '</div></ul></div>';
var loadOpen = layer.open({
type: 1,
title: '用户('+user+')项目列表',
area: '300px',
content:"<div class='bt-form pd20 c6'>\
<div>\
<div class='divtable' style='margin-top:5px;'>\
<table class='table table-hover'>\
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
<tbody>" + list + "</tbody>\
</table>" +
page +
"</div></div></div>"
});
});
}
function projectScript(user, name,has_hook){
// console.log(user,name,has_hook);
var html = '';
if (has_hook){
html += '<button onclick="projectScriptEdit(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">手动编辑</button>';
html += '<button onclick="projectScriptDebug(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">调试日志</button>';
html += '<button onclick="projectScriptLoad(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">重新加载</button>';
html += '<button onclick="projectScriptUnload(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">卸载脚本</button>';
} else {
html += '<button onclick="projectScriptLoad(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">加载脚本</button>';
}
var loadOpen = layer.open({
type: 1,
title: '['+user+']['+name+']脚本设置',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>'
});
}
function projectScriptEdit(user,name){
gogsPost('project_script_edit', {'user':user,'name':name}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['data']['path']);
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function projectScriptLoad(user,name){
gogsPost('project_script_load', {'user':user,'name':name}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
userProjectList(1);
}, 2000);
});
}
function projectScriptUnload(user,name){
gogsPost('project_script_unload', {'user':user,'name':name}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
userProjectList(1);
}, 2000);
});
}
function projectScriptDebug(user,name){
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function gogsRead(){
var readme = '<p>* 默认使用MySQL,第一个启动加载各种配置,并修改成正确的数据库配置</p>';
readme += '<p>* 邮件端口使用456,gogs仅支持使用STARTTLS的SMTP协议</p>';
$('.soft-man-con').html(readme);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 801 B

After

Width:  |  Height:  |  Size: 653 B

+7 -5
View File
@@ -1,11 +1,12 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="redisService();">服务</p>
<p onclick="redisConfig();">配置修改</p>
<p onclick="redisConfig();">切换版本</p>
<p onclick="redisStatus();">负载状态</p>
<p onclick="redisStatus();">性能调整</p>
<p class="bgw" onclick="pluginService('memcached');">服务</p>
<p onclick="pluginInitD('memcached');">自启动</p>
<p onclick="pluginConfig('memcached', null, 'conf_tpl');">配置模板</p>
<p onclick="pluginConfig('memcached');">配置文件</p>
<p onclick="memcachedStatus();">负载状态</p>
<p onclick="memcachedCache();">性能调整</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
@@ -14,5 +15,6 @@
</div>
<script type="text/javascript">
pluginService('memcached');
$.getScript( "/plugins/file?name=memcached&f=js/mem.js");
</script>
+197 -54
View File
@@ -4,87 +4,214 @@ import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.isAppleSystem():
app_debug = True
def getPluginName():
return 'memcached'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getConf():
path = getServerDir() + "/init.d/memcached"
return path
def getConfTpl():
path = getPluginDir() + "/init.d/memcached.tpl"
return path
def getMemPort():
path = getConf()
content = public.readFile(path)
rep = 'PORT\s*=\s*(\d*)'
tmp = re.search(rep, content)
return tmp.groups()[0]
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def status():
data = public.execShell(
"ps -ef|grep redis |grep -v grep | grep -v python | awk '{print $2}'")
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def start():
path = os.path.dirname(os.getcwd())
cmd = path + "/redis/bin/redis-server"
cmd = cmd + " " + path + "/redis/redis.conf"
data = public.execShell(cmd)
if data[0] == '':
def initDreplace():
file_tpl = getConfTpl()
service_path = public.getServerDir()
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/memcached'
if not os.path.exists(file_bin):
content = public.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path)
public.writeFile(file_bin, content)
public.execShell('chmod +x ' + file_bin)
return file_bin
def memOp(method):
file = initDreplace()
data = public.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return 'fail'
return data[1]
def start():
return memOp('start')
def stop():
data = public.execShell(
"ps -ef|grep redis |grep -v grep |grep -v python |awk '{print $2}' | xargs kill -9")
if data[0] == '':
return memOp('stop')
def restart():
return memOp('restart')
def reload():
return memOp('reload')
def runInfo():
# 获取memcached状态
import telnetlib
import re
port = getMemPort()
try:
tn = telnetlib.Telnet('127.0.0.1', int(port))
tn.write(b"stats\n")
tn.write(b"quit\n")
data = tn.read_all()
if type(data) == bytes:
data = data.decode('utf-8')
data = data.replace('STAT', '').replace('END', '').split("\n")
result = {}
res = ['cmd_get', 'get_hits', 'get_misses', 'limit_maxbytes', 'curr_items', 'bytes',
'evictions', 'limit_maxbytes', 'bytes_written', 'bytes_read', 'curr_connections']
for d in data:
if len(d) < 3:
continue
t = d.split()
if not t[0] in res:
continue
result[t[0]] = int(t[1])
result['hit'] = 1
if result['get_hits'] > 0 and result['cmd_get'] > 0:
result['hit'] = float(result['get_hits']) / \
float(result['cmd_get']) * 100
conf = public.readFile(getConf())
result['bind'] = re.search('IP=(.+)', conf).groups()[0]
result['port'] = int(re.search('PORT=(\d+)', conf).groups()[0])
result['maxconn'] = int(re.search('MAXCONN=(\d+)', conf).groups()[0])
result['cachesize'] = int(
re.search('CACHESIZE=(\d+)', conf).groups()[0])
return public.getJson(result)
except Exception, e:
return public.getJson({})
def saveConf():
# 设置memcached缓存大小
import re
confFile = getConf()
print confFile
try:
args = getArgs()
content = public.readFile(confFile)
content = re.sub('IP=.+', 'IP=' + args['ip'], content)
content = re.sub('PORT=\d+', 'PORT=' + args['port'], content)
content = re.sub('MAXCONN=\d+', 'MAXCONN=' + args['maxconn'], content)
content = re.sub('CACHESIZE=\d+', 'CACHESIZE=' +
args['cachesize'], content)
public.writeFile(confFile, content)
restart()
return 'save ok'
except Exception as e:
pass
return 'fail'
def initdStatus():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
return 'fail'
def restart():
def initdInstall():
import shutil
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
mem_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(mem_bin, initd_bin)
public.execShell('chmod +x ' + initd_bin)
return 'ok'
def reload():
def initdUinstall():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
initd_bin = getInitDFile()
os.remove(initd_bin)
return 'ok'
def runInfo():
path = os.path.dirname(os.getcwd())
cmd = path + "/redis/bin/redis-cli info"
data = public.execShell(cmd)[0]
res = [
'tcp_port',
'uptime_in_days', # 已运行天数
'connected_clients', # 连接的客户端数量
'used_memory', # Redis已分配的内存总量
'used_memory_rss', # Redis占用的系统内存总量
'used_memory_peak', # Redis所用内存的高峰值
'mem_fragmentation_ratio', # 内存碎片比率
'total_connections_received', # 运行以来连接过的客户端的总数量
'total_commands_processed', # 运行以来执行过的命令的总数量
'instantaneous_ops_per_sec', # 服务器每秒钟执行的命令数量
'keyspace_hits', # 查找数据库键成功的次数
'keyspace_misses', # 查找数据库键失败的次数
'latest_fork_usec' # 最近一次 fork() 操作耗费的毫秒数
]
data = data.split("\n")
result = {}
for d in data:
if len(d) < 3:
continue
t = d.strip().split(':')
if not t[0] in res:
continue
result[t[0]] = t[1]
return public.getJson(result)
def getConf():
path = os.path.dirname(os.getcwd()) + "/redis/redis.conf"
return path
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run_info':
print runInfo()
elif func == 'conf':
print getConf()
elif func == 'status':
if func == 'status':
print status()
elif func == 'start':
print start()
@@ -94,3 +221,19 @@ if __name__ == "__main__":
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 == 'run_info':
print runInfo()
elif func == 'conf':
print getConf()
elif func == 'conf_tpl':
print getConfTpl()
elif func == 'save_conf':
print saveConf()
else:
print 'fail'
+81
View File
@@ -0,0 +1,81 @@
#! /bin/bash
#
# memcached: MemCached Daemon
#
# chkconfig: - 90 25
# description: MemCached Daemon
#
### BEGIN INIT INFO
# Provides: memcached
# Required-Start: $syslog
# Required-Stop: $syslog
# Should-Start: $local_fs
# Should-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: memcached - Memory caching daemon
# Description: memcached - Memory caching daemon
### END INIT INFO
IP=127.0.0.1
PORT=11211
USER=root
MAXCONN=1024
CACHESIZE=64
OPTIONS=""
RETVAL=0
prog="memcached"
MEM_PATH={$SERVER_PATH}/memcached
start () {
echo -n $"Starting $prog: "
$MEM_PATH/bin/memcached -d -l $IP -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN -P $MEM_PATH/memcached.pid $OPTIONS
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
else
echo " done"
fi
}
stop () {
echo -n $"Stopping $prog: "
if [ ! -e $MEM_PATH/$prog.pid ]; then
echo -n $"$prog is not running."
exit 1
fi
kill `cat $MEM_PATH/memcached.pid`
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
else
rm -f ${MEM_PATH}/memcached.pid
echo " done"
fi
}
restart () {
$0 stop
sleep 2
$0 start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
;;
esac
exit $?
+9 -4
View File
@@ -13,23 +13,28 @@ install_tmp=${rootPath}/tmp/bt_install.pl
Install_mem()
{
mkdir -p $serverPath/tmp
mkdir -p $serverPath/source
echo '正在安装脚本文件...' > $install_tmp
wget -O $serverPath/tmp/memcached.tar.gz http://www.memcached.org/files/memcached-1.5.12.tar.gz
cd $serverPath/tmp && tar -zxvf memcached.tar.gz
if [ ! -f $serverPath/source/memcached.tar.gz ];then
wget -O $serverPath/source/memcached.tar.gz http://www.memcached.org/files/memcached-1.5.12.tar.gz
if
cd $serverPath/source && tar -zxvf memcached.tar.gz
mkdir -p $serverPath/memcached
cd memcached* && ./configure --prefix=$serverPath/memcached && make && make install
echo '1.5' > $serverPath/memcached/version.pl
echo '安装完成' > $install_tmp
#rm -rf $serverPath/tmp
}
Uninstall_mem()
{
$serverPath/memcached/init.d/memcached stop
rm -rf mkdir -p $serverPath/memcached
}
+38 -191
View File
@@ -1,188 +1,22 @@
function redisOp(a, b) {
var c = "name=" + a + "&func=" + b;
var d = "";
switch(b) {
case "stop":
d = '停止';
break;
case "start":
d = '启动';
break;
case "restart":
d = '重启';
break;
case "reload":
d = '重载';
break
}
layer.confirm( '您真的要{1}{2}服务吗?'.replace('{1}', d).replace('{2}', a), {icon:3,closeBtn: 2}, function() {
var e = layer.msg('正在{1}{2}服务,请稍候...'.replace('{1}', d).replace('{2}', a), {icon: 16,time: 0});
$.post("/plugins/run", c, function(g) {
layer.close(e);
var f = g.data == 'ok' ? '{1}服务已{2}'.replace('{1}', a).replace('{2}', d):'{1}服务{2}失败!'.replace('{1}', a).replace('{2}', d);
layer.msg(f, {icon: g.data == 'ok' ? 1 : 2});
if(b != "reload" && g.data == 'ok') {
if (b == 'start') {
setRedisService('redis', true);
} else if (b=='stop'){
setRedisService('redis', false);
} else {
}
}
if(g.data != 'ok') {
layer.msg(g.data, {icon: 2,time: 0,shade: 0.3,shadeClose: true});
}
},'json').error(function() {
layer.close(e);
layer.msg('操作成功!', {icon: 1});
});
})
}
//服务
function setRedisService(name, status){
var serviceCon ='<p class="status">当前状态:<span>'+(status ? '开启' : '关闭' )+
'</span><span style="color: '+
(status?'#20a53a;':'red;')+
' margin-left: 3px;" class="glyphicon ' + (status?'glyphicon glyphicon-play':'glyphicon-pause')+'"></span></p><div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="redisOp(\''+name+'\',\''+(status?'stop':'start')+'\')">'+(status?'停止':'启动')+'</button>\
<button class="btn btn-default btn-sm" onclick="redisOp(\''+name+'\',\'restart\')">重启</button>\
<button class="btn btn-default btn-sm" onclick="redisOp(\''+name+'\',\'reload\')">重载配置</button>\
</div>';
$(".soft-man-con").html(serviceCon);
}
//服务
function redisService(){
$.post('/plugins/run', {name:'redis', func:'status'}, function(data) {
console.log(data);
if(!data.status){
layer.msg(data.msg,{icon:0,time:3000,shade: [0.3, '#000']});
return;
}
if (data.data == 'start'){
setRedisService('redis', true);
} else {
setRedisService('redis', false);
}
},'json');
}
redisService();
//配置修改 --- start
function redisConfig(type){
var con = '<p style="color: #666; margin-bottom: 7px">提示:Ctrl+F 搜索关键字,Ctrl+G 查找下一个,Ctrl+S 保存,Ctrl+Shift+R 查找替换!</p><textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
<button id="OnlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">保存</button>\
<ul class="help-info-text c7 ptb15">\
<li>此处为redis主配置文件,若您不了解配置规则,请勿随意修改。</li>\
</ul>';
$(".soft-man-con").html(con);
var loadT = layer.msg('配置文件路径获取中...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/plugins/run', {name:'redis', func:'conf'},function (data) {
layer.close(loadT);
var loadT2 = layer.msg('文件内容获取中...',{icon:16,time:0,shade: [0.3, '#000']});
var fileName = data.data;
$.post('/files/get_body', 'path=' + fileName, function(rdata) {
layer.close(loadT2);
if (!rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$("#textBody").empty().text(rdata.data.data);
$(".CodeMirror").remove();
var editor = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-Space": "autocomplete",
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
redisConfSafe(fileName);
}
},
lineNumbers: true,
matchBrackets:true,
});
editor.focus();
$(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0});
$("#OnlineEditFileBtn").click(function(){
$("#textBody").text(editor.getValue());
redisConfSafe(fileName);
});
},'json');
},'json');
}
//配置保存
function redisConfSafe(fileName) {
var data = encodeURIComponent($("#textBody").val());
var encoding = 'utf-8';
var loadT = layer.msg('保存中...', {
icon: 16,
time: 0
});
$.post('/files/save_body', 'data=' + data + '&path=' + fileName + '&encoding=' + encoding, function(rdata) {
layer.close(loadT);
layer.msg(rdata.msg, {
icon: rdata.status ? 1 : 2
});
},'json');
}
//配置修改 --- end
//redis负载状态 start
function redisStatus() {
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'redis', func:'run_info'}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var rdata = $.parseJSON(data.data);
hit = (parseInt(rdata.keyspace_hits) / (parseInt(rdata.keyspace_hits) + parseInt(rdata.keyspace_misses)) * 100).toFixed(2);
var Con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
<tbody>\
<tr><th>uptime_in_days</th><td>' + rdata.uptime_in_days + '</td><td>已运行天数</td></tr>\
<tr><th>tcp_port</th><td>' + rdata.tcp_port + '</td><td>当前监听端口</td></tr>\
<tr><th>connected_clients</th><td>' + rdata.connected_clients + '</td><td>连接的客户端数量</td></tr>\
<tr><th>used_memory_rss</th><td>' + ToSize(rdata.used_memory_rss) + '</td><td>Redis当前占用的系统内存总量</td></tr>\
<tr><th>used_memory</th><td>' + ToSize(rdata.used_memory) + '</td><td>Redis当前已分配的内存总量</td></tr>\
<tr><th>used_memory_peak</th><td>' + ToSize(rdata.used_memory_peak) + '</td><td>Redis历史分配内存的峰值</td></tr>\
<tr><th>mem_fragmentation_ratio</th><td>' + rdata.mem_fragmentation_ratio + '%</td><td>内存碎片比率</td></tr>\
<tr><th>total_connections_received</th><td>' + rdata.total_connections_received + '</td><td>运行以来连接过的客户端的总数量</td></tr>\
<tr><th>total_commands_processed</th><td>' + rdata.total_commands_processed + '</td><td>运行以来执行过的命令的总数量</td></tr>\
<tr><th>instantaneous_ops_per_sec</th><td>' + rdata.instantaneous_ops_per_sec + '</td><td>服务器每秒钟执行的命令数量</td></tr>\
<tr><th>keyspace_hits</th><td>' + rdata.keyspace_hits + '</td><td>查找数据库键成功的次数</td></tr>\
<tr><th>keyspace_misses</th><td>' + rdata.keyspace_misses + '</td><td>查找数据库键失败的次数</td></tr>\
<tr><th>hit</th><td>' + hit + '%</td><td>查找数据库键命中率</td></tr>\
<tr><th>latest_fork_usec</th><td>' + rdata.latest_fork_usec + '</td><td>最近一次 fork() 操作耗费的微秒数</td></tr>\
<tbody>\
</table></div>'
$(".soft-man-con").html(Con);
},'json');
}
//redis负载状态 end
//memcached负载状态
function MemcachedStatus() {
function memcachedStatus() {
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.get('/ajax?action=GetMemcachedStatus', function(rdata) {
layer.close(loadT);
$.post('/plugins/run', {name:'memcached', func:'run_info'}, function(data) {
layer.close(loadT);
if (!data.status){
showMsg(data.msg, function(){}, null,13000);
return;
}
var rdata = $.parseJSON(data.data);
if ($.isEmptyObject(rdata)){
showMsg('memcached服务没有启动!', function(){}, undefined, 3000);
return;
}
var Con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
@@ -198,33 +32,45 @@ function MemcachedStatus() {
<tr><th>hit</th><td>' + rdata.hit.toFixed(2) + '%</td><td>GET命中率</td></tr>\
<tr><th>curr_items</th><td>' + rdata.curr_items + '</td><td>当前被缓存的数据行数</td></tr>\
<tr><th>evictions</th><td>' + rdata.evictions + '</td><td>因内存不足而被清理的缓存行数</td></tr>\
<tr><th>bytes</th><td>' + ToSize(rdata.bytes) + '</td><td>当前已使用内存</td></tr>\
<tr><th>bytes_read</th><td>' + ToSize(rdata.bytes_read) + '</td><td>请求总大小</td></tr>\
<tr><th>bytes_written</th><td>' + ToSize(rdata.bytes_written) + '</td><td>发送总大小</td></tr>\
<tr><th>bytes</th><td>' + toSize(rdata.bytes) + '</td><td>当前已使用内存</td></tr>\
<tr><th>bytes_read</th><td>' + toSize(rdata.bytes_read) + '</td><td>请求总大小</td></tr>\
<tr><th>bytes_written</th><td>' + toSize(rdata.bytes_written) + '</td><td>发送总大小</td></tr>\
<tbody>\
</table></div>'
$(".soft-man-con").html(Con);
});
},'json');
}
//memcached性能调整
function MemcachedCache() {
function memcachedCache() {
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.get('/ajax?action=GetMemcachedStatus', function(rdata) {
$.post('/plugins/run', {name:'memcached', func:'run_info'}, function(data) {
layer.close(loadT);
if (!data.status){
showMsg(data.msg, function(){}, null,13000);
return;
}
var rdata = $.parseJSON(data.data);
if ($.isEmptyObject(rdata)){
showMsg('memcached服务没有启动!', function(){}, undefined, 3000);
return;
}
var memCon = '<div class="conf_p" style="margin-bottom:0">\
<p><span>BindIP</span><input style="width: 120px;" class="bt-input-text mr5" name="membind" value="' + rdata.bind + '" type="text" ><font>监听IP,请勿随意修改</font></p>\
<p><span>PORT</span><input style="width: 120px;" class="bt-input-text mr5" max="65535" name="memport" value="' + rdata.port + '" type="number" ><font>监听端口,一般无需修改</font></p>\
<p><span>CACHESIZE</span><input style="width: 120px;" class="bt-input-text mr5" name="memcachesize" value="' + rdata.cachesize + '" type="number" >MB,<font>缓存大小,建议不要大于512M</font></p>\
<p><span>MAXCONN</span><input style="width: 120px;" class="bt-input-text mr5" name="memmaxconn" value="' + rdata.maxconn + '" type="number" ><font>最大连接数,建议不要大于40960</font></p>\
<div style="margin-top:10px; padding-right:230px" class="text-right"><button class="btn btn-success btn-sm" onclick="SetMemcachedConf()">' + lan.public.save + '</button></div>\
<div style="margin-top:10px; padding-right:230px" class="text-right"><button class="btn btn-success btn-sm" onclick="setMemcachedConf()">保存</button></div>\
</div>'
$(".soft-man-con").html(memCon);
});
},'json');
}
//memcached提交配置
function SetMemcachedConf() {
function setMemcachedConf() {
var data = {
ip: $("input[name='membind']").val(),
port: $("input[name='memport']").val(),
@@ -251,9 +97,10 @@ function SetMemcachedConf() {
layer.msg('最大连接数过小', { icon: 2 });
return;
}
var loadT = layer.msg('正在保存...', { icon: 16, time: 0, shade: 0.3 });
$.post('/ajax?action=SetMemcachedCache', data, function(rdata) {
$.post('/plugins/run', {name:'memcached', func:'save_conf',args:JSON.stringify(data) }, function(rdata) {
layer.close(loadT);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
},'json');
}
+86
View File
@@ -0,0 +1,86 @@
# coding: utf-8
import re
import os
import sys
sys.path.append("/usr/local/lib/python2.7/site-packages")
class mysql:
__DB_PASS = None
__DB_USER = 'root'
__DB_PORT = 3306
__DB_HOST = 'localhost'
__DB_CONN = None
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
def __Conn(self):
'''连接MYSQL数据库'''
try:
import public
socket = '/tmp/mysql.sock'
try:
import MySQLdb
except Exception, ex:
self.__DB_ERR = ex
return False
try:
myconf = public.readFile(self.__DB_CNF)
rep = "port\s*=\s*([0-9]+)"
self.__DB_PORT = int(re.search(rep, myconf).groups()[0])
except:
self.__DB_PORT = 3306
# print self.__DB_PASS
#self.__DB_PASS = public.M('config').where('id=?', (1,)).getField('mysql_root')
try:
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=socket)
except MySQLdb.Error, e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=socket)
self.__DB_CUR = self.__DB_CONN.cursor()
return True
except MySQLdb.Error, e:
self.__DB_ERR = e
return False
def setPwd(self, pwd):
self.__DB_PASS = pwd
def getPwd(self):
return self.__DB_PASS
def execute(self, sql):
# 执行SQL语句返回受影响行
if not self.__Conn():
return self.__DB_ERR
try:
result = self.__DB_CUR.execute(sql)
self.__DB_CONN.commit()
self.__Close()
return result
except Exception, ex:
return ex
def query(self, sql):
# 执行SQL语句返回数据集
if not self.__Conn():
return self.__DB_ERR
try:
self.__DB_CUR.execute(sql)
result = self.__DB_CUR.fetchall()
# 将元组转换成列表
data = map(list, result)
self.__Close()
return data
except Exception, ex:
return ex
# 关闭连接
def __Close(self):
self.__DB_CUR.close()
self.__DB_CONN.close()
+70
View File
@@ -0,0 +1,70 @@
[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
socket = /tmp/mysql.sock
datadir = {$SERVER_APP_PATH}/data
log-error = {$SERVER_APP_PATH}/data/error.log
default_storage_engine = MyISAM
#skip-external-locking
#loose-skip-innodb
key_buffer_size = 8M
max_allowed_packet = 100G
table_open_cache = 32
sort_buffer_size = 256K
net_buffer_length = 4K
read_buffer_size = 128K
read_rnd_buffer_size = 256K
myisam_sort_buffer_size = 4M
thread_cache_size = 4
query_cache_size = 4M
tmp_table_size = 8M
#skip-networking
#skip-name-resolve
max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
log-bin=mysql-bin
binlog_format=mixed
server-id = 1
expire_logs_days = 10
slow_query_log=1
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
long_query_time=3
#log_queries_not_using_indexes=on
default_storage_engine = InnoDB
innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
innodb_buffer_pool_size = 16M
innodb_additional_mem_pool_size = 2M
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90
innodb_read_io_threads = 1
innodb_write_io_threads = 1
innodb_file_per_table=1
[mysqldump]
quick
max_allowed_packet = 16M
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M
[mysqlhotcopy]
interactive-timeout
+17
View File
@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS `config` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`mysql_root` TEXT
);
INSERT INTO `config` (`id`, `mysql_root`) VALUES (1, 'admin');
CREATE TABLE IF NOT EXISTS `databases` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
`name` TEXT,
`username` TEXT,
`password` TEXT,
`accept` TEXT,
`ps` TEXT,
`addtime` TEXT
);
+36 -534
View File
@@ -1,550 +1,52 @@
<style>
/*危险按钮*/
.bts-danger:hover{
color: #fff;
background-color: #c9302c;
border-color: #ac2925;
<style type="text/css">
.db_list{
padding: 0px 0 10px 0;
font-size: 13px;
line-height: 35px;
height: 45px;
}
#whiteList a{
color: red;
.db_list a{
margin-right: 15px;
color: #555;
font-weight: 600;
}
/*弹窗*/
.Add_view{
height: 100px;
padding-left: 35px;
padding-top: 35px;
}
.Add_view label{
margin-right: 10px;
font-size: 15px;
font-weight: 100;
}
.Add_view input{
width: 230px;
}
.Add_view .error{
border: 1px solid red;
}
.Add_view .correct{
border: 1px solid #20a53a;
}
/*日志管理*/
.btnTitle{
font-weight: 100;
font-size: 16px;
line-height: 34px;
height: 34px;
margin-right: 15px;
position: relative;
top: 2px;
}
.whiteList-table{
margin-top: 10px;
}
/*登录日志表单*/
.viewTwo .whiteList-table{
overflow-x: hidden;
height: 500px;
}
.maks{
background: rgba(39, 39, 39, 0.4);
position: absolute;
width: 700px;
height: 555px;
z-index: 999;
overflow: hidden;
}
.boxshow{
position: absolute;
height: 150px;
width: 400px;
margin-left: -200px;
margin-top: -75px;
left: 50%;
top: 50%;
z-index: 1000;
background: #fff;
padding: 25px 20px;
overflow: hidden;
}
.btPayment {
.db_list span:nth-child(1){
display: block;
float: left;
padding: 8px 10px;
width: 190px;
height: 100px;
line-height: 33px;
text-align: center;
border-left: 1px solid #ececec;
padding-left: 15px;
background: #ececec;
border-radius: 3px;
}
.btPayment .t2{
display: block;
width: 100%;
text-align: center;
font-size: 16px;
margin-bottom: 5px;
#db_tools button {
margin-right: 10px;
}
.btPayment .price{
color: #20A53A;
font-size: 22px;
margin: 0 5px;
}
.bt-form{
overflow: hidden;
}
.boxtext{
line-height: 32px;
margin-top: -17px;
text-align: center;
border-bottom: #eee 1px solid;
height: 39px;
font-size: 14px;
#db_tools button:last-child{
margin-right: 0;
}
</style>
<div class="maks" style="display: none"></div>
<div class="boxshow" style="display: none;">
<div>
<div class="boxtext">
<span>未开通此服务,如需使用请开通企业运维版。</span>
</div>
<div class="btvipinfo" style="width: 170px;padding-left: 20px">
<p style="height: 25px">1、一对一运维人员对接</p>
<p style="height: 25px">2、提供每月3次运维服务</p>
<p style="height: 25px">3、双重安全隔离登录</p>
</div>
<div class="btPayment">
<span class="t2">企业运维版<span class="price">98</span>元/月</span>
<button class="btn btn-success btn-sm" style="width:80%" onclick="window.open('https://www.bt.cn/admin/index.html')">立即开通</button>
</div>
</div>
</div>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw">密钥</p>
<p>面板设置</p>
<p>面板登录日志</p>
<p>SSH设置</p>
<p>SSH日志管理</p>
<p class="bgw" onclick="pluginService('mysql');">服务</p>
<p onclick="pluginInitD('mysql');">自启动</p>
<p onclick="pluginConfig('mysql');">配置文件</p>
<p onclick="myPort();">端口</p>
<p onclick="runInfo();">当前状态</p>
<p onclick="myPerfOpt();">性能优化</p>
<p onclick="myLogs();">日志</p>
<p onclick="pluginLogs('mysql','','show_log');">慢日志</p>
<p onclick="dbList()">管理列表</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con viewZoo">
<p class="status" style="margin-top:10px;margin-left:10px;height: 80px;margin-bottom:15px;">
<span style="float:left;margin-top:-5px">密钥:</span>
<textarea class="bt-input-text" name="token" readonly="readonly" style="background-color: #eee;width:400px;height:80px;padding: 8px 15px;" placeholder="密钥已隐藏..."></textarea>
</p>
<input type="button" class="btn btn-success btn-sm" name="ButtonShow" style="margin-left:52px;width:100px" onclick="sagelogin.tokenShow()" value="显示密钥" />
<ul style="margin: 15px 5px;padding-left: 70px;list-style-type: disc;line-height: 25px;">
<li>宝塔企业运维后台连接您的服务器需要此密钥,请妥善记录并保存</li>
<li>一但密钥丢失,可能导致您无法登录服务器</li>
</ul>
</div>
<div class="soft-man-con viewOne" style="display: none;">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play"></span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除面板登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('面板白名单',true)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListOne"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewTwo" style="display: none">
<div class="whiteList-table divtable">
<table class="table table-hover" style=" max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>操作记录</th>
<th>操作时间</th>
</tr>
</thead>
<tbody id="whiteListTwo"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewThree" style="display: none">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play">
</span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除SSH登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('SSH白名单',false)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListThree"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewFour" style="display: none">
<div class="btnclick">
<label class="btnTitle">日志分类</label>
<div class="btn-group">
<input type="submit" name="btnOne" class="btn btn-success" onclick="sagelogin.SSH_Defense_List(0)" value="已防御" />
<input type="submit" name="btnTwo" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(1)" value="入侵日志"/>
<input type="submit" name="btnThree" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(2)" value="登录日志"/>
</div>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 470px;">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>源IP地址</th>
<th>用户</th>
<th style="text-align: right;">登录时间</th>
</tr>
</thead>
<tbody id="whiteListFour"></tbody>
</table>
</div>
</div>
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="javascript/text">
//宝塔安全登录
$(function(){
$(".bt-w-menu p").click(function(){
$(this).addClass("bgw").siblings().removeClass("bgw");
$('.bt-w-con .soft-man-con').hide().eq($(this).index()).show();
switch($(this).index()) {
case 0:
break;
case 1:
sagelogin.Panel_White_List();
break;
case 2:
sagelogin.Panel_journal();
break;
case 3:
sagelogin.SSH_White_List();
break;
case 4:
sagelogin.SSH_Defense_List(0);
break;
}
});
layer.load();
$.get('/plugin?action=a&name=safelogin&s=GetServerInfo',function(data) {
layer.closeAll('loading');
if (data.status) {
$('.boxshow').hide();
$('.maks').hide();
}else{
$('.boxshow').show();
$('.maks').show();
}
});
});
var sagelogin = new Object();
sagelogin = {
Addview:'',
SSHlogList:'',
PanelLogList:'',
// SSH管理
SSH_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?',{icon: 1}, {
btn: ['确认','取消'],
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_ssh_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.SSH_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
tokenShow:function(){
var inputPwd = layer.open({
type: 1,
title: '验证面板密码',
shadeClose: true,
shade: 0.3,
area: ['380px', '190px'],
btn:['确定','取消'],
content:'<div class="Add_view" style="height:90px"><label>面板密码:</label><input name="panel_pwd" class=" bt-input-text" type="password"></div>',
yes:function(){
var passwordStr = $("input[name='panel_pwd']").val();
var index = layer.load(0, {shade: false});
$.post('/plugin?action=a&name=safelogin&s=GetServerToken',{password:passwordStr},function(token) {
layer.close(index);
if(token.status === false){
layer.msg(token.msg,{icon:2});
return;
}
layer.close(inputPwd);
$("textarea[name='token']").val(token);
});
},
btn2:function(){
layer.close(inputPwd);
}
});
},
// SSH白名单——列表
SSH_White_List:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_ssh_limit','',function(data){
$('#whiteListThree').empty();
var List = '';
if (data.length == 0){
$('.viewThree .status span:eq(0)').html('关闭');
$('.viewThree .glyphicon-pause').show();
$('.viewThree .glyphicon-play').hide();
}else {
$('.viewThree .status span:eq(0)').html('开启');
$('.viewThree .glyphicon-pause').hide();
$('.viewThree .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.SSH_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListThree').append(List);
layer.close(index);
});
},
// SSH白名单——删除
SSH_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// SSH白名单——添加
SSH_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_ssh_limit',{ip:ip},function(data){
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// SSH日志管理
SSH_Defense_List:function(status){
$('.btnclick input').removeClass('btn-success').addClass('btn-default');
$('.btnclick input').eq(status).addClass('btn-success').removeClass('btn-default');
if (sagelogin.SSHlogList == '') {
$.get('/plugin?action=a&s=get_ssh_errorlogin&name=safelogin',function(data){
sagelogin.SSHlogList = data;
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
});
}else{
switch(status) {
case 0:
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
break;
case 1:
sagelogin.DefenseFor(sagelogin.SSHlogList.intrusion);
break;
case 2:
sagelogin.DefenseFor(sagelogin.SSHlogList.success);
break;
}
}
},
// SSH日志渲染模板
DefenseFor:function(data){
var List = '';
$('#whiteListFour').empty();
for (var i = data.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+data[i].address+'</td><td>' + data[i].user + '</td><td style="text-align:right">'+ data[i].date+'</td></tr>'
}
$('#whiteListFour').append(List);
},
// 面板管理
Panel_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_panel_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.Panel_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——列表
Panel_White_List:function(){
$.get('/plugin?action=a&name=safelogin&s=get_panel_limit','',function(data){
$('#whiteListOne').empty();
var List = '';
if (data.length == 0){
$('.viewOne .status span:eq(0)').html('关闭');
$('.viewOne .glyphicon-pause').show();
$('.viewOne .glyphicon-play').hide();
}else {
$('.viewOne .status span:eq(0)').html('开启');
$('.viewOne .glyphicon-pause').hide();
$('.viewOne .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.Panel_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListOne').append(List);
});
},
// 面板白名单——删除
Panel_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——添加
Panel_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_panel_limit', {ip: ip}, function(data) {
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// 面板日志——列表
Panel_journal:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_login_log',function(data){
$('#whiteListTwo').empty();
var List = '';
sagelogin.PanelLogList = data;
for (var i = sagelogin.PanelLogList.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+ sagelogin.PanelLogList[i].log +'</td><td style="text-align:right;">'+ sagelogin.PanelLogList[i].addtime +'</tr>';
}
$('#whiteListTwo').append(List);
layer.close(index);
});
},
// IP正则:192.168.1.0/24
CheckIP:function(ip) {
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\/\d{1,2})?$/;
return reg.test(ip);
},
CheckIPTwo:function(ip) {
var reg = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/gi;
return reg.test(ip);
},
// 添加表单效验
addViewVul:function(status){
var ip = $('.addViewVul');
if (status) {
console.log(sagelogin.CheckIP(ip.val()));
if(sagelogin.CheckIPTwo(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}else{
if(sagelogin.CheckIP(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}
},
// 添加界面
Add_view:function(title,status){
var _this = this;
var text = ''
var statuss = true;
if (status) {
text = '';
statuss = true;
}else{
text = '<p style="color:red;margin: 5px 0px 0px 67px;font-size: 14px;">支持IP段,如:192.168.1.0/24</p>';
statuss = false;
}
sagelogin.Addview = layer.open({
type: 1,
title: title,
shadeClose: true,
shade: 0.1,
area: ['380px', '200px'],
btn:['确定','取消'],
content:'<div class="Add_view"><label>IP地址:</label><input class="addViewVul bt-input-text" onchange="sagelogin.addViewVul('+ statuss +')" type="text">'+ text +'</div>',
yes:function(){
if (sagelogin.addViewVul(statuss)) {
if(status){
sagelogin.Panel_Add_White_List($('.addViewVul').val());
}else{
sagelogin.SSH_Add_White_List($('.addViewVul').val());
}
}else{
layer.msg('请输入合法的IP地址',{icon:2})
}
},
btn2:function(){
layer.close(sagelogin.Addview);
}
});
$('.addViewVul').focus();
}
}
</div>
<script type="text/javascript">
resetPluginWinWidth(800);
pluginService('mysql');
$.getScript( "/plugins/file?name=mysql&f=js/mysql.js");
</script>
+972 -173
View File
File diff suppressed because it is too large Load Diff
+6 -8
View File
@@ -4,14 +4,12 @@
"name":"mysql",
"type":"运行环境",
"ps":"MySQL是一种关系数据库管理系统!",
"versions":["5.5"],
"updates":["5.5"],
"versions":["5.5","5.6","5.7","8.0"],
"updates":["5.5.62"],
"shell":"install.sh",
"checks":"/www/server/panel/plugin/safelogin",
"author":"midoks",
"home":"http://www.bt.cn/bbs",
"checks":"server/mysql",
"author":"mysql",
"home":"https://dev.mysql.com/downloads/mysql",
"date":"2017-11-24",
"default":true,
"display":1,
"pid": "1"
"pid": "2"
}
+379
View File
@@ -0,0 +1,379 @@
#!/bin/sh
# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
# This file is public domain and comes with NO WARRANTY of any kind
# MySQL daemon start/stop script.
# Usually this is put in /etc/init.d (at least on machines SYSV R4 based
# systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/K01mysql.
# When this is done the mysql server will be started when the machine is
# started and shut down when the systems goes down.
# Comments to support chkconfig on RedHat Linux
# chkconfig: 2345 64 36
# description: A very fast and reliable SQL database engine.
# Comments to support LSB init script conventions
### BEGIN INIT INFO
# Provides: mysql
# Required-Start: $local_fs $network $remote_fs
# Should-Start: ypbind nscd ldap ntpd xntpd
# Required-Stop: $local_fs $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop MySQL
# Description: MySQL is a very fast and reliable SQL database engine.
### END INIT INFO
# If you install MySQL on some other places than /www/server/mysql, then you
# have to do one of the following things for this script to work:
#
# - Run this script from within the MySQL installation directory
# - Create a /etc/my.cnf file with the following information:
# [mysqld]
# basedir=<path-to-mysql-installation-directory>
# - Add the above to any other configuration file (for example ~/.my.ini)
# and copy my_print_defaults to /usr/bin
# - Add the path to the mysql-installation-directory to the basedir variable
# below.
#
# If you want to affect other MySQL variables, you should make your changes
# in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files.
# If you change base dir, you must also change datadir. These may get
# overwritten by settings in the MySQL configuration files.
basedir=
datadir=
# Default value, in seconds, afterwhich the script should timeout waiting
# for server start.
# Value here is overriden by value in my.cnf.
# 0 means don't wait at all
# Negative numbers mean to wait indefinitely
service_startup_timeout=900
# Lock directory for RedHat / SuSE.
lockdir='/var/lock/subsys'
lock_file_path="$lockdir/mysql"
# The following variables are only set for letting mysql.server find things.
# Set some defaults
mysqld_pid_file_path=
if test -z "$basedir"
then
basedir={$SERVER_APP_PATH}
bindir={$SERVER_APP_PATH}/bin
if test -z "$datadir"
then
datadir={$SERVER_APP_PATH}/data
fi
sbindir={$SERVER_APP_PATH}/bin
libexecdir={$SERVER_APP_PATH}/bin
else
bindir="$basedir/bin"
if test -z "$datadir"
then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
fi
# datadir_set is used to determine if datadir was set (and so should be
# *not* set inside of the --basedir= handler.)
datadir_set=
#
# Use LSB init script functions for printing messages, if possible
#
lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions ; then
. $lsb_functions
else
log_success_msg()
{
echo " SUCCESS! $@"
}
log_failure_msg()
{
echo " ERROR! $@"
}
fi
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
export PATH
mode=$1 # start or stop
[ $# -ge 1 ] && shift
other_args=--sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" # uncommon, but needed when called from an RPM upgrade action
# Expected: "--skip-networking --skip-grant-tables"
# They are not checked here, intentionally, as it is the resposibility
# of the "spec" file author to give correct arguments only.
case `echo "testing\c"`,`echo -n testing` in
*c*,-n*) echo_n= echo_c= ;;
*c*,*) echo_n=-n echo_c= ;;
*) echo_n= echo_c='\c' ;;
esac
parse_server_arguments() {
for arg do
case "$arg" in
--basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
bindir="$basedir/bin"
if test -z "$datadir_set"; then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
;;
--datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'`
datadir_set=1
;;
--pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
--service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
esac
done
}
wait_for_pid () {
verb="$1" # created | removed
pid="$2" # process ID of the program operating on the pid-file
pid_file_path="$3" # path to the PID file.
i=0
avoid_race_condition="by checking again"
while test $i -ne $service_startup_timeout ; do
case "$verb" in
'created')
# wait for a PID-file to pop into existence.
test -s "$pid_file_path" && i='' && break
;;
'removed')
# wait for this PID-file to disappear
test ! -s "$pid_file_path" && i='' && break
;;
*)
echo "wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path"
exit 1
;;
esac
# if server isn't running, then pid-file will never be updated
if test -n "$pid"; then
if kill -0 "$pid" 2>/dev/null; then
: # the server still runs
else
# The server may have exited between the last pid-file check and now.
if test -n "$avoid_race_condition"; then
avoid_race_condition=""
continue # Check again.
fi
# there's nothing that will affect the file.
log_failure_msg "The server quit without updating PID file ($pid_file_path)."
return 1 # not waiting any more.
fi
fi
echo $echo_n ".$echo_c"
i=`expr $i + 1`
sleep 1
done
if test -z "$i" ; then
log_success_msg
return 0
else
log_failure_msg
return 1
fi
}
# Get arguments from the my.cnf file,
# the only group, which is read from now on is [mysqld]
if test -x "$bindir/my_print_defaults"; then
print_defaults="$bindir/my_print_defaults"
else
# Try to find basedir in /etc/my.cnf
conf=/etc/my.cnf
print_defaults=
if test -r $conf
then
subpat='^[^=]*basedir[^=]*=\(.*\)$'
dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf`
for d in $dirs
do
d=`echo $d | sed -e 's/[ ]//g'`
if test -x "$d/bin/my_print_defaults"
then
print_defaults="$d/bin/my_print_defaults"
break
fi
done
fi
# Hope it's in the PATH ... but I doubt it
test -z "$print_defaults" && print_defaults="my_print_defaults"
fi
#
# Read defaults file from 'basedir'. If there is no defaults file there
# check if it's in the old (depricated) place (datadir) and read it from there
#
extra_args=""
if test -r "$basedir/my.cnf"
then
extra_args="-e $basedir/my.cnf"
else
if test -r "$datadir/my.cnf"
then
extra_args="-e $datadir/my.cnf"
fi
fi
parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
#
# Set pid file if not given
#
if test -z "$mysqld_pid_file_path"
then
mysqld_pid_file_path=$datadir/`hostname`.pid
else
case "$mysqld_pid_file_path" in
/* ) ;;
* ) mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;;
esac
fi
#ulimit -s unlimited
case "$mode" in
'start')
# Start daemon
# Safeguard (relative paths, core dumps..)
cd $basedir
echo $echo_n "Starting MySQL"
if test -x $bindir/mysqld_safe
then
# Give extra arguments to mysqld with the my.cnf file. This script
# may be overwritten at next upgrade.
$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null &
wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$?
# Make lock for RedHat / SuSE
if test -w "$lockdir"
then
touch "$lock_file_path"
fi
exit $return_value
else
log_failure_msg "Couldn't find MySQL server ($bindir/mysqld_safe)"
fi
;;
'stop')
# Stop daemon. We use a signal here to avoid having to know the
# root password.
if test -s "$mysqld_pid_file_path"
then
mysqld_pid=`cat "$mysqld_pid_file_path"`
if (kill -0 $mysqld_pid 2>/dev/null)
then
echo $echo_n "Shutting down MySQL"
kill $mysqld_pid
# mysqld should remove the pid file when it exits, so wait for it.
wait_for_pid removed "$mysqld_pid" "$mysqld_pid_file_path"; return_value=$?
else
log_failure_msg "MySQL server process #$mysqld_pid is not running!"
rm "$mysqld_pid_file_path"
fi
# Delete lock for RedHat / SuSE
if test -f "$lock_file_path"
then
rm -f "$lock_file_path"
fi
exit $return_value
else
log_failure_msg "MySQL server PID file could not be found!"
fi
;;
'restart')
# Stop the service and regardless of whether it was
# running or not, start it again.
if $0 stop $other_args; then
$0 start $other_args
else
log_failure_msg "Failed to stop running server, so refusing to try to start."
exit 1
fi
;;
'reload'|'force-reload')
if test -s "$mysqld_pid_file_path" ; then
read mysqld_pid < "$mysqld_pid_file_path"
kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL"
touch "$mysqld_pid_file_path"
else
log_failure_msg "MySQL PID file could not be found!"
exit 1
fi
;;
'status')
# First, check to see if pid file exists
if test -s "$mysqld_pid_file_path" ; then
read mysqld_pid < "$mysqld_pid_file_path"
if kill -0 $mysqld_pid 2>/dev/null ; then
log_success_msg "MySQL running ($mysqld_pid)"
exit 0
else
log_failure_msg "MySQL is not running, but PID file exists"
exit 1
fi
else
# Try to find appropriate mysqld process
mysqld_pid=`pidof $libexecdir/mysqld`
# test if multiple pids exist
pid_count=`echo $mysqld_pid | wc -w`
if test $pid_count -gt 1 ; then
log_failure_msg "Multiple MySQL running but PID file could not be found ($mysqld_pid)"
exit 5
elif test -z $mysqld_pid ; then
if test -f "$lock_file_path" ; then
log_failure_msg "MySQL is not running, but lock file ($lock_file_path) exists"
exit 2
fi
log_failure_msg "MySQL is not running"
exit 3
else
log_failure_msg "MySQL is running but PID file could not be found"
exit 4
fi
fi
;;
*)
# usage
basename=`basename "$0"`
echo "Usage: $basename {start|stop|restart|reload|force-reload|status} [ MySQL server options ]"
exit 1
;;
esac
exit 0
+17 -30
View File
@@ -1,40 +1,27 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
install_tmp='/tmp/bt_install.pl'
public_file=/www/server/panel/install/public.sh
if [ ! -f $public_file ];then
wget -O $public_file http://download.bt.cn/install/public.sh -T 5;
fi
. $public_file
download_Url=$NODE_URL
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
Install_safelogin()
{
mkdir -p /www/server/panel/plugin/safelogin
echo '正在安装脚本文件...' > $install_tmp
wget -O /www/server/panel/plugin/safelogin/safelogin_main.py $download_Url/install/lib/plugin/safelogin/safelogin_main.py -T 5
wget -O /www/server/panel/plugin/safelogin/index.html $download_Url/install/lib/plugin/safelogin/index.html -T 5
wget -O /www/server/panel/plugin/safelogin/info.json $download_Url/install/lib/plugin/safelogin/info.json -T 5
wget -O /www/server/panel/plugin/safelogin/icon.png $download_Url/install/lib/plugin/safelogin/icon.png -T 5
echo '安装完成' > $install_tmp
}
Uninstall_safelogin()
{
chattr -i /www/server/panel/plugin/safelogin/token.pl
rm -f /www/server/panel/data/limitip.conf
sed -i "/ALL/d" /etc/hosts.deny
rm -rf /www/server/panel/plugin/safelogin
}
install_tmp=${rootPath}/tmp/bt_install.pl
action=$1
host=$2;
if [ "${1}" == 'install' ];then
Install_safelogin
else
Uninstall_safelogin
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
+913 -246
View File
File diff suppressed because it is too large Load Diff
+66
View File
@@ -0,0 +1,66 @@
#!/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")
install_tmp=${rootPath}/tmp/bt_install.pl
mysqlDir=${serverPath}/source/mysql
Install_mysql()
{
mkdir -p ${mysqlDir}
echo '正在安装脚本文件...' > $install_tmp
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
groupadd mysql
useradd -g mysql mysql
if [ ! -f ${mysqlDir}/mysql-5.5.62.tar.gz ];then
wget -O ${mysqlDir}/mysql-5.5.62.tar.gz https://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.62.tar.gz
fi
if [ ! -f ${mysqlDir}/mysql-5.5.62 ];then
cd ${mysqlDir} && tar -zxvf ${mysqlDir}/mysql-5.5.62.tar.gz
fi
cd ${mysqlDir}/mysql-5.5.62 && cmake \
-DCMAKE_INSTALL_PREFIX=$serverPath/mysql \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DMYSQL_UNIX_ADDR=/var/tmp/mysql.sock \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
&& make && make install && make clean \
&& echo '5.5' > $serverPath/mysql/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_mysql()
{
#rm -rf $serverPath/mysql
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_mysql
else
Uninstall_mysql
fi
+77
View File
@@ -0,0 +1,77 @@
user {$OS_USER} {$OS_USER_GROUP};
worker_processes auto;
error_log {$SERVER_PATH}/openresty/nginx/logs/error.log crit;
pid {$SERVER_PATH}/openresty/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
events
{
use {$EVENT_MODEL};
worker_connections 51200;
multi_accept on;
}
http
{
include mime.types;
#include luawaf.conf;
#include proxy.conf;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$request_time"';
server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server_tokens off;
access_log off;
server {
listen 80;
server_name 127.0.0.1;
allow 127.0.0.1;
location /nginx_status {
stub_status on;
access_log off;
}
include {$SERVER_PATH}/openresty/nginx/conf/php_status/*.conf;
}
include {$SERVER_PATH}/web_conf/nginx/vhost/*.conf;
}
+9 -541
View File
@@ -1,550 +1,18 @@
<style>
/*危险按钮*/
.bts-danger:hover{
color: #fff;
background-color: #c9302c;
border-color: #ac2925;
}
#whiteList a{
color: red;
}
/*弹窗*/
.Add_view{
height: 100px;
padding-left: 35px;
padding-top: 35px;
}
.Add_view label{
margin-right: 10px;
font-size: 15px;
font-weight: 100;
}
.Add_view input{
width: 230px;
}
.Add_view .error{
border: 1px solid red;
}
.Add_view .correct{
border: 1px solid #20a53a;
}
/*日志管理*/
.btnTitle{
font-weight: 100;
font-size: 16px;
line-height: 34px;
height: 34px;
margin-right: 15px;
position: relative;
top: 2px;
}
.whiteList-table{
margin-top: 10px;
}
/*登录日志表单*/
.viewTwo .whiteList-table{
overflow-x: hidden;
height: 500px;
}
.maks{
background: rgba(39, 39, 39, 0.4);
position: absolute;
width: 700px;
height: 555px;
z-index: 999;
overflow: hidden;
}
.boxshow{
position: absolute;
height: 150px;
width: 400px;
margin-left: -200px;
margin-top: -75px;
left: 50%;
top: 50%;
z-index: 1000;
background: #fff;
padding: 25px 20px;
overflow: hidden;
}
.btPayment {
float: left;
padding: 8px 10px;
width: 190px;
height: 100px;
line-height: 33px;
text-align: center;
border-left: 1px solid #ececec;
}
.btPayment .t2{
display: block;
width: 100%;
text-align: center;
font-size: 16px;
margin-bottom: 5px;
}
.btPayment .price{
color: #20A53A;
font-size: 22px;
margin: 0 5px;
}
.bt-form{
overflow: hidden;
}
.boxtext{
line-height: 32px;
margin-top: -17px;
text-align: center;
border-bottom: #eee 1px solid;
height: 39px;
font-size: 14px;
}
</style>
<div class="maks" style="display: none"></div>
<div class="boxshow" style="display: none;">
<div>
<div class="boxtext">
<span>未开通此服务,如需使用请开通企业运维版。</span>
</div>
<div class="btvipinfo" style="width: 170px;padding-left: 20px">
<p style="height: 25px">1、一对一运维人员对接</p>
<p style="height: 25px">2、提供每月3次运维服务</p>
<p style="height: 25px">3、双重安全隔离登录</p>
</div>
<div class="btPayment">
<span class="t2">企业运维版<span class="price">98</span>元/月</span>
<button class="btn btn-success btn-sm" style="width:80%" onclick="window.open('https://www.bt.cn/admin/index.html')">立即开通</button>
</div>
</div>
</div>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw">密钥</p>
<p>面板设置</p>
<p>面板登录日志</p>
<p>SSH设置</p>
<p>SSH日志管理</p>
<p class="bgw" onclick="orPluginService('openresty');">服务</p>
<p onclick="pluginInitD('openresty');">自启动</p>
<p onclick="pluginConfig('openresty');">配置修改</p>
<p onclick="getOpenrestyStatus();">负载状态</p>
<p onclick="pluginLogs('openresty');">错误日志</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con viewZoo">
<p class="status" style="margin-top:10px;margin-left:10px;height: 80px;margin-bottom:15px;">
<span style="float:left;margin-top:-5px">密钥:</span>
<textarea class="bt-input-text" name="token" readonly="readonly" style="background-color: #eee;width:400px;height:80px;padding: 8px 15px;" placeholder="密钥已隐藏..."></textarea>
</p>
<input type="button" class="btn btn-success btn-sm" name="ButtonShow" style="margin-left:52px;width:100px" onclick="sagelogin.tokenShow()" value="显示密钥" />
<ul style="margin: 15px 5px;padding-left: 70px;list-style-type: disc;line-height: 25px;">
<li>宝塔企业运维后台连接您的服务器需要此密钥,请妥善记录并保存</li>
<li>一但密钥丢失,可能导致您无法登录服务器</li>
</ul>
</div>
<div class="soft-man-con viewOne" style="display: none;">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play"></span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除面板登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('面板白名单',true)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListOne"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewTwo" style="display: none">
<div class="whiteList-table divtable">
<table class="table table-hover" style=" max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>操作记录</th>
<th>操作时间</th>
</tr>
</thead>
<tbody id="whiteListTwo"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewThree" style="display: none">
<p class="status">当前状态:
<span>开启</span>
<span style="color: #20a53a; margin-left: 3px;" class="glyphicon glyphicon glyphicon-play">
</span>
<span style="color: red; margin-left: 3px; display: none" class="glyphicon glyphicon-pause"></span>
</p>
<div class="sfm-opt">
<button class="btn btn-default btn-sm bts-danger" onclick="sagelogin.Panel_Admin()">清除SSH登录限制IP</button>
<button class="btn btn-default btn-sm bts-safety" onclick="sagelogin.Add_view('SSH白名单',false)">添加白名单</button>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 420px">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>IP地址</th>
<th style="text-align: right;">操作</th>
</tr>
</thead>
<tbody id="whiteListThree"></tbody>
</table>
</div>
</div>
<div class="soft-man-con viewFour" style="display: none">
<div class="btnclick">
<label class="btnTitle">日志分类</label>
<div class="btn-group">
<input type="submit" name="btnOne" class="btn btn-success" onclick="sagelogin.SSH_Defense_List(0)" value="已防御" />
<input type="submit" name="btnTwo" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(1)" value="入侵日志"/>
<input type="submit" name="btnThree" class="btn btn-default" onclick="sagelogin.SSH_Defense_List(2)" value="登录日志"/>
</div>
</div>
<div class="whiteList-table divtable" style="overflow-x: hidden;height: 470px;">
<table class="table table-hover" style="max-height: 380px; overflow: auto;">
<thead>
<tr>
<th>源IP地址</th>
<th>用户</th>
<th style="text-align: right;">登录时间</th>
</tr>
</thead>
<tbody id="whiteListFour"></tbody>
</table>
</div>
</div>
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="javascript/text">
//宝塔安全登录
$(function(){
$(".bt-w-menu p").click(function(){
$(this).addClass("bgw").siblings().removeClass("bgw");
$('.bt-w-con .soft-man-con').hide().eq($(this).index()).show();
switch($(this).index()) {
case 0:
break;
case 1:
sagelogin.Panel_White_List();
break;
case 2:
sagelogin.Panel_journal();
break;
case 3:
sagelogin.SSH_White_List();
break;
case 4:
sagelogin.SSH_Defense_List(0);
break;
}
});
layer.load();
$.get('/plugin?action=a&name=safelogin&s=GetServerInfo',function(data) {
layer.closeAll('loading');
if (data.status) {
$('.boxshow').hide();
$('.maks').hide();
}else{
$('.boxshow').show();
$('.maks').show();
}
});
});
var sagelogin = new Object();
sagelogin = {
Addview:'',
SSHlogList:'',
PanelLogList:'',
// SSH管理
SSH_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?',{icon: 1}, {
btn: ['确认','取消'],
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_ssh_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.SSH_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
tokenShow:function(){
var inputPwd = layer.open({
type: 1,
title: '验证面板密码',
shadeClose: true,
shade: 0.3,
area: ['380px', '190px'],
btn:['确定','取消'],
content:'<div class="Add_view" style="height:90px"><label>面板密码:</label><input name="panel_pwd" class=" bt-input-text" type="password"></div>',
yes:function(){
var passwordStr = $("input[name='panel_pwd']").val();
var index = layer.load(0, {shade: false});
$.post('/plugin?action=a&name=safelogin&s=GetServerToken',{password:passwordStr},function(token) {
layer.close(index);
if(token.status === false){
layer.msg(token.msg,{icon:2});
return;
}
layer.close(inputPwd);
$("textarea[name='token']").val(token);
});
},
btn2:function(){
layer.close(inputPwd);
}
});
},
// SSH白名单——列表
SSH_White_List:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_ssh_limit','',function(data){
$('#whiteListThree').empty();
var List = '';
if (data.length == 0){
$('.viewThree .status span:eq(0)').html('关闭');
$('.viewThree .glyphicon-pause').show();
$('.viewThree .glyphicon-play').hide();
}else {
$('.viewThree .status span:eq(0)').html('开启');
$('.viewThree .glyphicon-pause').hide();
$('.viewThree .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.SSH_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListThree').append(List);
layer.close(index);
});
},
// SSH白名单——删除
SSH_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// SSH白名单——添加
SSH_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_ssh_limit',{ip:ip},function(data){
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.SSH_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// SSH日志管理
SSH_Defense_List:function(status){
$('.btnclick input').removeClass('btn-success').addClass('btn-default');
$('.btnclick input').eq(status).addClass('btn-success').removeClass('btn-default');
if (sagelogin.SSHlogList == '') {
$.get('/plugin?action=a&s=get_ssh_errorlogin&name=safelogin',function(data){
sagelogin.SSHlogList = data;
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
});
}else{
switch(status) {
case 0:
sagelogin.DefenseFor(sagelogin.SSHlogList.defense);
break;
case 1:
sagelogin.DefenseFor(sagelogin.SSHlogList.intrusion);
break;
case 2:
sagelogin.DefenseFor(sagelogin.SSHlogList.success);
break;
}
}
},
// SSH日志渲染模板
DefenseFor:function(data){
var List = '';
$('#whiteListFour').empty();
for (var i = data.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+data[i].address+'</td><td>' + data[i].user + '</td><td style="text-align:right">'+ data[i].date+'</td></tr>'
}
$('#whiteListFour').append(List);
},
// 面板管理
Panel_Admin:function(){
var confirm = layer.confirm('确定清除面板登录限制IP地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=close_panel_limit',function(data) {
if (data.status) {
layer.msg(data.msg,{icon:1});
sagelogin.Panel_White_List();
}else{
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——列表
Panel_White_List:function(){
$.get('/plugin?action=a&name=safelogin&s=get_panel_limit','',function(data){
$('#whiteListOne').empty();
var List = '';
if (data.length == 0){
$('.viewOne .status span:eq(0)').html('关闭');
$('.viewOne .glyphicon-pause').show();
$('.viewOne .glyphicon-play').hide();
}else {
$('.viewOne .status span:eq(0)').html('开启');
$('.viewOne .glyphicon-pause').hide();
$('.viewOne .glyphicon-play').show();
}
for (var i = 0; i < data.length; i++) {
List = List + '<tr><td>'+ data[i] +'</td><td style="text-align:right;"><a href="javascript:;" ip-val="'+ data[i] +'" onclick="sagelogin.Panel_Del_White_List(event)" style="color:red">删除</a></td></tr>'
}
$('#whiteListOne').append(List);
});
},
// 面板白名单——删除
Panel_Del_White_List:function(ev){
var ip = ev.currentTarget.getAttribute('ip-val');
var confirm = layer.confirm('确定删除IP['+ ip +']限制地址?', {
btn: ['确认','取消'] //按钮
}, function(){
$.get('/plugin?action=a&name=safelogin&s=remove_ssh_limit',{ip:ip},function(data){
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else {
layer.msg(data.msg,{icon:2});
}
});
}, function(){
layer.close(confirm);
});
},
// 面板白名单——添加
Panel_Add_White_List:function(ip){
$.post('/plugin?action=a&name=safelogin&s=add_panel_limit', {ip: ip}, function(data) {
layer.close(sagelogin.Addview);
if (data.status) {
sagelogin.Panel_White_List();
layer.msg(data.msg,{icon:1});
}else{
layer.msg(data.msg,{icon:2});
}
});
},
// 面板日志——列表
Panel_journal:function(){
var index = layer.load(0, {shade: false});
$.get('/plugin?action=a&name=safelogin&s=get_login_log',function(data){
$('#whiteListTwo').empty();
var List = '';
sagelogin.PanelLogList = data;
for (var i = sagelogin.PanelLogList.length - 1; i >= 0; i--) {
List = List + '<tr><td>'+ sagelogin.PanelLogList[i].log +'</td><td style="text-align:right;">'+ sagelogin.PanelLogList[i].addtime +'</tr>';
}
$('#whiteListTwo').append(List);
layer.close(index);
});
},
// IP正则:192.168.1.0/24
CheckIP:function(ip) {
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\/\d{1,2})?$/;
return reg.test(ip);
},
CheckIPTwo:function(ip) {
var reg = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/gi;
return reg.test(ip);
},
// 添加表单效验
addViewVul:function(status){
var ip = $('.addViewVul');
if (status) {
console.log(sagelogin.CheckIP(ip.val()));
if(sagelogin.CheckIPTwo(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}else{
if(sagelogin.CheckIP(ip.val())){
ip.addClass('correct').removeClass('error');
return true;
}else {
ip.addClass('error').removeClass('correct');
return false;
}
}
},
// 添加界面
Add_view:function(title,status){
var _this = this;
var text = ''
var statuss = true;
if (status) {
text = '';
statuss = true;
}else{
text = '<p style="color:red;margin: 5px 0px 0px 67px;font-size: 14px;">支持IP段,如:192.168.1.0/24</p>';
statuss = false;
}
sagelogin.Addview = layer.open({
type: 1,
title: title,
shadeClose: true,
shade: 0.1,
area: ['380px', '200px'],
btn:['确定','取消'],
content:'<div class="Add_view"><label>IP地址:</label><input class="addViewVul bt-input-text" onchange="sagelogin.addViewVul('+ statuss +')" type="text">'+ text +'</div>',
yes:function(){
if (sagelogin.addViewVul(statuss)) {
if(status){
sagelogin.Panel_Add_White_List($('.addViewVul').val());
}else{
sagelogin.SSH_Add_White_List($('.addViewVul').val());
}
}else{
layer.msg('请输入合法的IP地址',{icon:2})
}
},
btn2:function(){
layer.close(sagelogin.Addview);
}
});
$('.addViewVul').focus();
}
}
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=openresty&f=js/openresty.js");
</script>
+296
View File
@@ -0,0 +1,296 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.isAppleSystem():
app_debug = True
def getPluginName():
return 'openresty'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def clearTemp():
path_bin = getServerDir() + "/nginx"
public.execShell('rm -rf ' + path_bin + '/client_body_temp')
public.execShell('rm -rf ' + path_bin + '/fastcgi_temp')
public.execShell('rm -rf ' + path_bin + '/proxy_temp')
public.execShell('rm -rf ' + path_bin + '/scgi_temp')
public.execShell('rm -rf ' + path_bin + '/uwsgi_temp')
def getConf():
path = getServerDir() + "/nginx/conf/nginx.conf"
return path
def getConfTpl():
path = getPluginDir() + '/conf/nginx.conf'
return path
def getOs():
data = {}
data['os'] = public.getOs()
ng_exe_bin = getServerDir() + "/nginx/sbin/nginx"
if checkAuthEq(ng_exe_bin, 'root'):
data['auth'] = True
else:
data['auth'] = False
return public.getJson(data)
def getInitDTpl():
path = getPluginDir() + "/init.d/nginx.tpl"
return path
def makeConf():
vhost = getServerDir() + '/nginx/conf/vhost'
if not os.path.exists(vhost):
os.mkdir(vhost)
php_status = getServerDir() + '/nginx/conf/php_status'
if not os.path.exists(php_status):
os.mkdir(php_status)
def getFileOwner(filename):
import pwd
stat = os.lstat(filename)
uid = stat.st_uid
pw = pwd.getpwuid(uid)
return pw.pw_name
def checkAuthEq(file, owner='root'):
fowner = getFileOwner(file)
if (fowner == owner):
return True
return False
def confReplace():
service_path = os.path.dirname(os.getcwd())
content = public.readFile(getConfTpl())
content = content.replace('{$SERVER_PATH}', service_path)
user = 'www'
user_group = 'www'
if public.getOs() == 'darwin':
# macosx do
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
# user = 'root'
user_group = 'staff'
content = content.replace('{$EVENT_MODEL}', 'kqueue')
else:
content = content.replace('{$EVENT_MODEL}', 'epoll')
content = content.replace('{$OS_USER}', user)
content = content.replace('{$OS_USER_GROUP}', user_group)
public.writeFile(getServerDir() + '/nginx/conf/nginx.conf', content)
# give nginx root permission
ng_exe_bin = getServerDir() + "/nginx/sbin/nginx"
if not checkAuthEq(ng_exe_bin, 'root'):
args = getArgs()
sudoPwd = args['pwd']
cmd_own = 'chown -R ' + 'root:' + user_group + ' ' + ng_exe_bin
os.system('echo %s|sudo -S %s' % (sudoPwd, cmd_own))
cmd_mod = 'chmod 755 ' + ng_exe_bin
os.system('echo %s|sudo -S %s' % (sudoPwd, cmd_mod))
cmd_s = 'chmod u+s ' + ng_exe_bin
os.system('echo %s|sudo -S %s' % (sudoPwd, cmd_s))
def initDreplace():
file_tpl = getInitDTpl()
service_path = os.path.dirname(os.getcwd())
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
content = public.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path)
public.writeFile(file_bin, content)
public.execShell('chmod +x ' + file_bin)
# config replace
confReplace()
# make nginx vhost or other
makeConf()
return file_bin
def status():
data = public.execShell(
"ps -ef|grep nginx |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def start():
file = initDreplace()
data = public.execShell(file + ' start')
if data[1] == '':
return 'ok'
return data[1]
def stop():
file = initDreplace()
data = public.execShell(file + ' stop')
clearTemp()
if data[1] == '':
return 'ok'
return data[1]
def restart():
file = initDreplace()
data = public.execShell(file + ' restart')
if data[1] == '':
return 'ok'
return data[1]
def reload():
file = initDreplace()
data = public.execShell(file + ' reload')
if data[1] == '':
return 'ok'
return data[1]
def initdStatus():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
public.execShell('chmod +x ' + initd_bin)
return 'ok'
def initdUinstall():
if not app_debug:
if public.isAppleSystem():
return "Apple Computer does not support"
initd_bin = getInitDFile()
os.remove(initd_bin)
return 'ok'
def runInfo():
# 取Openresty负载状态
try:
result = public.httpGet('http://127.0.0.1/nginx_status')
tmp = result.split()
data = {}
data['active'] = tmp[2]
data['accepts'] = tmp[9]
data['handled'] = tmp[7]
data['requests'] = tmp[8]
data['Reading'] = tmp[11]
data['Writing'] = tmp[13]
data['Waiting'] = tmp[15]
return public.getJson(data)
except Exception as e:
return 'oprenresty not started'
def errorLogPath():
return getServerDir() + '/nginx/logs/error.log'
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 == 'get_os':
print getOs()
elif func == 'run_info':
print runInfo()
elif func == 'error_log':
print errorLogPath()
else:
print 'error'
+118
View File
@@ -0,0 +1,118 @@
#! /bin/sh
# chkconfig: 2345 55 25
# Description: Startup script for nginx webserver on Debian. Place in /etc/init.d and
# run 'update-rc.d -f nginx defaults', or use the appropriate command on your
# distro. For CentOS/Redhat run: 'chkconfig --add nginx'
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=nginx
NGINX_BIN={$SERVER_PATH}/openresty/bin/openresty
CONFIGFILE={$SERVER_PATH}/openresty/nginx/conf/$NAME.conf
PIDFILE={$SERVER_PATH}/openresty/nginx/logs/$NAME.pid
case "$1" in
start)
echo -n "Starting $NAME... "
if [ -f $PIDFILE ];then
mPID=`cat $PIDFILE`
isStart=`ps ax | awk '{ print $1 }' | grep -e "^${mPID}$"`
if [ "$isStart" != '' ];then
echo "$NAME (pid `pidof $NAME`) already running."
exit 1
fi
fi
$NGINX_BIN -c $CONFIGFILE
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
stop)
echo -n "Stoping $NAME... "
if [ -f $PIDFILE ];then
mPID=`cat $PIDFILE`
isStart=`ps ax | awk '{ print $1 }' | grep -e "^${mPID}$"`
if [ "$isStart" = '' ];then
echo "$NAME is not running."
exit 1
fi
else
echo "$NAME is not running."
exit 1
fi
$NGINX_BIN -s stop
if [ "$?" != 0 ] ; then
echo " failed. Use force-quit"
exit 1
else
echo " done"
fi
;;
status)
if [ -f $PIDFILE ];then
mPID=`cat $PIDFILE`
isStart=`ps ax | awk '{ print $1 }' | grep -e "^${mPID}$"`
if [ "$isStart" != '' ];then
echo "$NAME (pid `pidof $NAME`) already running."
exit 1
else
echo "$NAME is stopped"
exit 0
fi
else
echo "$NAME is stopped"
exit 0
fi
;;
restart)
$0 stop
sleep 1
$0 start
;;
reload)
echo -n "Reload service $NAME... "
if [ -f $PIDFILE ];then
mPID=`cat $PIDFILE`
isStart=`ps ax | awk '{ print $1 }' | grep -e "^${mPID}$"`
if [ "$isStart" != '' ];then
$NGINX_BIN -s reload
echo " done"
else
echo "$NAME is not running, can't reload."
exit 1
fi
else
echo "$NAME is not running, can't reload."
exit 1
fi
;;
configtest)
echo -n "Test $NAME configure files... "
$NGINX_BIN -t
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status|configtest}"
exit 1
;;
esac
+19 -29
View File
@@ -7,36 +7,26 @@ rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/bt_install.pl
openrestyDir=${serverPath}/source/openresty
Install_openresty()
{
mkdir -p ${openrestyDir}
echo '正在安装脚本文件...' > $install_tmp
if [ ! -f ${openrestyDir}/openresty-1.13.6.2.tar.gz ];then
wget -O ${openrestyDir}/openresty-1.13.6.2.tar.gz https://openresty.org/download/openresty-1.13.6.2.tar.gz
fi
cd ${openrestyDir} && tar -zxvf openresty-1.13.6.2.tar.gz
cd ${openrestyDir}/openresty* && ./configure --prefix=$serverPath/openresty \
--with-openssl=$serverPath/source/lib/openssl-1.0.2q && make && make install
echo '安装完成' > $install_tmp
}
Uninstall_openresty()
{
rm -rf $serverPath/openresty
echo '卸载完成' > $install_tmp
}
action=$1
host=$2
if [ "${1}" == 'install' ];then
Install_openresty
type=$2
if id www &> /dev/null ;then
echo "www UID is `id -u www`"
echo "www Shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
else
Uninstall_openresty
groupadd www
useradd -g www -s /sbin/nologin www
fi
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
+188 -75
View File
@@ -1,3 +1,134 @@
orPluginService('openresty');
function orPost(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'openresty', func:method, args:JSON.stringify(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 orPluginService(_name, version){
var data = {name:_name, func:'status'}
if ( typeof(version) != 'undefined' ){
data['version'] = version;
} else {
version = '';
}
orPost('status', data, function(data){
if (data.data == 'start'){
orPluginSetService(_name, true, version);
} else {
orPluginSetService(_name, false, version);
}
});
}
function orPluginSetService(_name ,status, version){
var serviceCon ='<p class="status">当前状态:<span>'+(status ? '开启' : '关闭' )+
'</span><span style="color: '+
(status?'#20a53a;':'red;')+
' margin-left: 3px;" class="glyphicon ' + (status?'glyphicon glyphicon-play':'glyphicon-pause')+'"></span></p><div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\''+(status?'stop':'start')+'\',\''+version+'\')">'+(status?'停止':'启动')+'</button>\
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\'restart\',\''+version+'\')">重启</button>\
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\'reload\',\''+version+'\')">重载配置</button>\
</div>';
$(".soft-man-con").html(serviceCon);
}
function orPluginOpService(a, b, v) {
var c = "name=" + a + "&func=" + b;
if(v != ''){
c = c + '&version='+v;
}
var d = "";
switch(b) {
case "stop":d = '停止';break;
case "start":d = '启动';break;
case "restart":d = '重启';break;
case "reload":d = '重载';break;
}
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,v]), {icon:3,closeBtn: 2}, function() {
orPost('get_os',{},function(data){
var rdata = $.parseJSON(data.data);
if (!rdata['auth']){
layer.prompt({title: '检查到权限不足,需要输入密码!', formType: 1},function(pwd, index){
layer.close(index);
var data = {'pwd':pwd};
c += '&args='+JSON.stringify(data);
orPluginOpServiceOp(a,b,c,d,a,v);
});
} else {
orPluginOpServiceOp(a,b,c,d,a,v);
}
});
})
}
function orPluginOpServiceOp(a,b,c,d,a,v){
var e = layer.msg(msgTpl('正在{1}{2}{3}服务,请稍候...',[d,a,v]), {icon: 16,time: 0});
$.post("/plugins/run", c, function(g) {
layer.close(e);
var f = g.data == 'ok' ? msgTpl('{1}{2}服务已{3}',[a,v,d]) : msgTpl('{1}{2}服务{3}失败!',[a,v,d]);
layer.msg(f, {icon: g.data == 'ok' ? 1 : 2});
if( b != "reload" && g.data == 'ok' ) {
if ( b == 'start' ) {
orPluginSetService(a, true, v);
} else if ( b == 'stop' ){
orPluginSetService(a, false, v);
}
}
if( g.status && g.data != 'ok' ) {
layer.msg(g.data, {icon: 2,time: 3000,shade: 0.3,shadeClose: true});
}
},'json').error(function() {
layer.close(e);
layer.msg('操作异常!', {icon: 2});
});
}
//查看Nginx负载状态
function getOpenrestyStatus() {
$.post('/plugins/run', {name:'openresty', func:'run_info'}, function(data) {
if (!data.status){
showMsg(data.msg, function(){}, null,3000);
return;
}
try {
var rdata = $.parseJSON(data.data);
var con = "<div><table class='table table-hover table-bordered'>\
<tr><th>活动连接(Active connections)</th><td>" + rdata.active + "</td></tr>\
<tr><th>总连接次数(accepts)</th><td>" + rdata.accepts + "</td></tr>\
<tr><th>总握手次数(handled)</th><td>" + rdata.handled + "</td></tr>\
<tr><th>总请求数(requests)</th><td>" + rdata.requests + "</td></tr>\
<tr><th>请求数(Reading)</th><td>" + rdata.Reading + "</td></tr>\
<tr><th>响应数(Writing)</th><td>" + rdata.Writing + "</td></tr>\
<tr><th>驻留进程(Waiting)</th><td>" + rdata.Waiting + "</td></tr>\
</table></div>";
$(".soft-man-con").html(con);
}catch(err){
showMsg(data.data, function(){}, null,3000);
}
},'json');
}
//nginx
function nginxSoftMain(name, version) {
@@ -24,18 +155,18 @@ function nginxSoftMain(name, version) {
closeBtn: 2,
shift: 0,
content: '<div class="bt-w-main" style="width:640px;">\
<div class="bt-w-menu">\
<p class="bgw" onclick="service(\'' + name + '\',' + nameA.status + ')">' + lan.soft.web_service + '</p>\
<p onclick="configChange(\'' + name + '\')">' + lan.soft.config_edit + '</p>\
' + waf + '\
' + menu + '\
' + status + '\
<p onclick="showLogs(\'' + logsPath + '\')">错误日志</p>\
</div>\
<div id="webEdit-con" class="bt-w-con pd15" style="height:555px;overflow:auto">\
<div class="soft-man-con"></div>\
</div>\
</div>'
<div class="bt-w-menu">\
<p class="bgw" onclick="service(\'' + name + '\',' + nameA.status + ')">' + lan.soft.web_service + '</p>\
<p onclick="configChange(\'' + name + '\')">' + lan.soft.config_edit + '</p>\
' + waf + '\
' + menu + '\
' + status + '\
<p onclick="showLogs(\'' + logsPath + '\')">错误日志</p>\
</div>\
<div id="webEdit-con" class="bt-w-con pd15" style="height:555px;overflow:auto">\
<div class="soft-man-con"></div>\
</div>\
</div>'
});
service(name, nameA.status);
$(".bt-w-menu p").click(function() {
@@ -83,42 +214,42 @@ function waf() {
var cc = rdata.CCrate.split('/')
var con = "<div class='wafConf'>\
<div class='wafConf-btn'>\
<span>" + lan.soft.waf_title + "</span><div class='ssh-item'>\
<div class='wafConf-btn'>\
<span>" + lan.soft.waf_title + "</span><div class='ssh-item'>\
<input class='btswitch btswitch-ios' id='closeWaf' type='checkbox' " + (rdata.status == 1 ? 'checked' : '') + ">\
<label class='btswitch-btn' for='closeWaf' onclick='CloseWaf()'></label>\
</div>\
<div class='pull-right'>\
<button class='btn btn-default btn-sm' onclick='gzEdit()'>" + lan.soft.waf_edit + "</button>\
<button class='btn btn-default btn-sm' onclick='upLimit()'>" + lan.soft.waf_up_title + "</button>\
</div>\
</div>\
<div class='wafConf_checkbox label-input-group ptb10 relative'>\
<input type='checkbox' id='waf_UrlDeny' " + (rdata['UrlDeny'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('UrlDeny','" + (rdata['UrlDeny'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_UrlDeny'>" + lan.soft.waf_input1 + "</label>\
<input type='checkbox' id='waf_CookieMatch' " + (rdata['CookieMatch'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('CookieMatch','" + (rdata['CookieMatch'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_CookieMatch'>" + lan.soft.waf_input2 + "</label>\
<input type='checkbox' id='waf_postMatch' " + (rdata['postMatch'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('postMatch','" + (rdata['postMatch'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_postMatch'>" + lan.soft.waf_input3 + "</label>\
<input type='checkbox' id='waf_CCDeny' " + (rdata['CCDeny'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('CCDeny','" + (rdata['CCDeny'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_CCDeny'>" + lan.soft.waf_input4 + "</label>\
<input type='checkbox' id='waf_attacklog' " + (rdata['attacklog'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('attacklog','" + (rdata['attacklog'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_attacklog'>" + lan.soft.waf_input5 + "</label>\
<span class='glyphicon glyphicon-folder-open' style='position: absolute; right: 10px; top: 12px; color: orange;cursor: pointer' onclick='openPath(\"/www/wwwlogs/waf\")'></span>\
</div>\
<div class='wafConf_cc'>\
<span>" + lan.soft.waf_input6 + "</span><input id='CCrate_1' class='bt-input-text' type='number' value='" + cc[0] + "' style='width:80px;margin-right:30px'/>\
<span>" + lan.soft.waf_input7 + "(" + lan.bt.s + ")</span><input id='CCrate_2' class='bt-input-text' type='number' value='" + cc[1] + "' style='width:80px;'/>\
<button onclick=\"SetWafConfig('CCrate','')\" class='btn btn-default btn-sm'>" + lan.public.ok + "</button>\
</div>\
<div class='wafConf_ip'>\
<fieldset>\
<legend>" + lan.soft.waf_input8 + "</legend>\
<input type='text' id='ipWhitelist_val' class='bt-input-text mr5' placeholder='" + lan.soft.waf_ip + "' style='width:175px;' /><button onclick=\"addWafKey('ipWhitelist')\" class='btn btn-default btn-sm'>" + lan.public.add + "</button>\
<div class='table-overflow'><table class='table table-hover'>" + whiteList + "</table></div>\
</fieldset>\
<fieldset>\
<legend>" + lan.soft.waf_input9 + "</legend>\
<input type='text' id='ipBlocklist_val' class='bt-input-text mr5' placeholder='" + lan.soft.waf_ip + "' style='width:175px;' /><button onclick=\"addWafKey('ipBlocklist')\" class='btn btn-default btn-sm'>" + lan.public.add + "</button>\
<div class='table-overflow'><table class='table table-hover'>" + blackList + "</table></div>\
</fieldset>\
</div>\
</div>"
</div>\
<div class='pull-right'>\
<button class='btn btn-default btn-sm' onclick='gzEdit()'>" + lan.soft.waf_edit + "</button>\
<button class='btn btn-default btn-sm' onclick='upLimit()'>" + lan.soft.waf_up_title + "</button>\
</div>\
</div>\
<div class='wafConf_checkbox label-input-group ptb10 relative'>\
<input type='checkbox' id='waf_UrlDeny' " + (rdata['UrlDeny'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('UrlDeny','" + (rdata['UrlDeny'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_UrlDeny'>" + lan.soft.waf_input1 + "</label>\
<input type='checkbox' id='waf_CookieMatch' " + (rdata['CookieMatch'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('CookieMatch','" + (rdata['CookieMatch'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_CookieMatch'>" + lan.soft.waf_input2 + "</label>\
<input type='checkbox' id='waf_postMatch' " + (rdata['postMatch'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('postMatch','" + (rdata['postMatch'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_postMatch'>" + lan.soft.waf_input3 + "</label>\
<input type='checkbox' id='waf_CCDeny' " + (rdata['CCDeny'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('CCDeny','" + (rdata['CCDeny'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_CCDeny'>" + lan.soft.waf_input4 + "</label>\
<input type='checkbox' id='waf_attacklog' " + (rdata['attacklog'] == 'on' ? 'checked' : '') + " onclick=\"SetWafConfig('attacklog','" + (rdata['attacklog'] == 'on' ? 'off' : 'on') + "')\" /><label for='waf_attacklog'>" + lan.soft.waf_input5 + "</label>\
<span class='glyphicon glyphicon-folder-open' style='position: absolute; right: 10px; top: 12px; color: orange;cursor: pointer' onclick='openPath(\"/www/wwwlogs/waf\")'></span>\
</div>\
<div class='wafConf_cc'>\
<span>" + lan.soft.waf_input6 + "</span><input id='CCrate_1' class='bt-input-text' type='number' value='" + cc[0] + "' style='width:80px;margin-right:30px'/>\
<span>" + lan.soft.waf_input7 + "(" + lan.bt.s + ")</span><input id='CCrate_2' class='bt-input-text' type='number' value='" + cc[1] + "' style='width:80px;'/>\
<button onclick=\"SetWafConfig('CCrate','')\" class='btn btn-default btn-sm'>" + lan.public.ok + "</button>\
</div>\
<div class='wafConf_ip'>\
<fieldset>\
<legend>" + lan.soft.waf_input8 + "</legend>\
<input type='text' id='ipWhitelist_val' class='bt-input-text mr5' placeholder='" + lan.soft.waf_ip + "' style='width:175px;' /><button onclick=\"addWafKey('ipWhitelist')\" class='btn btn-default btn-sm'>" + lan.public.add + "</button>\
<div class='table-overflow'><table class='table table-hover'>" + whiteList + "</table></div>\
</fieldset>\
<fieldset>\
<legend>" + lan.soft.waf_input9 + "</legend>\
<input type='text' id='ipBlocklist_val' class='bt-input-text mr5' placeholder='" + lan.soft.waf_ip + "' style='width:175px;' /><button onclick=\"addWafKey('ipBlocklist')\" class='btn btn-default btn-sm'>" + lan.public.add + "</button>\
<div class='table-overflow'><table class='table table-hover'>" + blackList + "</table></div>\
</fieldset>\
</div>\
</div>"
$(".soft-man-con").html(con);
});
}
@@ -158,7 +289,7 @@ function upLimit() {
}
//设置waf状态
function CloseWaf() {
function closeWaf() {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/waf?action=SetStatus', '', function(rdata) {
layer.close(loadT)
@@ -168,8 +299,8 @@ function CloseWaf() {
}
//取规则文件
function GetWafFile(name) {
OnlineEditFile(0, '/www/server/panel/vhost/wafconf/' + name);
function getWafFile(name) {
onlineEditFile(0, '/www/server/panel/vhost/wafconf/' + name);
}
//规则编辑
function gzEdit() {
@@ -180,13 +311,13 @@ function gzEdit() {
closeBtn: 2,
shift: 0,
content: "<div class='gzEdit'><button class='btn btn-default btn-sm' onclick=\"GetWafFile('cookie')\">Cookie</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('post')\">POST</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('url')\">URL</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('user-agent')\">User-Agent</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('args')\">Args</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('whiteurl')\">" + lan.soft.waf_url_white + "</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('returnhtml')\">" + lan.soft.waf_index + "</button>\
<button class='btn btn-default btn-sm' onclick=\"updateWaf('returnhtml')\">" + lan.soft.waf_cloud + "</button></div>"
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('post')\">POST</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('url')\">URL</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('user-agent')\">User-Agent</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('args')\">Args</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('whiteurl')\">" + lan.soft.waf_url_white + "</button>\
<button class='btn btn-default btn-sm' onclick=\"GetWafFile('returnhtml')\">" + lan.soft.waf_index + "</button>\
<button class='btn btn-default btn-sm' onclick=\"updateWaf('returnhtml')\">" + lan.soft.waf_cloud + "</button></div>"
});
}
@@ -200,7 +331,7 @@ function updateWaf() {
}
//设置WAF配置值
function SetWafConfig(name, value) {
function setWafConfig(name, value) {
if (name == 'CCrate') {
var CCrate_1 = $("#CCrate_1").val();
var CCrate_2 = $("#CCrate_2").val();
@@ -242,21 +373,3 @@ function addWafKey(name) {
if (name == 'black_fileExt') upLimit();
});
}
//查看Nginx负载状态
function GetNginxStatus() {
$.post('/ajax?action=GetNginxStatus', '', function(rdata) {
var con = "<div><table class='table table-hover table-bordered'>\
<tr><th>" + lan.bt.nginx_active + "</th><td>" + rdata.active + "</td></tr>\
<tr><th>" + lan.bt.nginx_accepts + "</th><td>" + rdata.accepts + "</td></tr>\
<tr><th>" + lan.bt.nginx_handled + "</th><td>" + rdata.handled + "</td></tr>\
<tr><th>" + lan.bt.nginx_requests + "</th><td>" + rdata.requests + "</td></tr>\
<tr><th>" + lan.bt.nginx_reading + "</th><td>" + rdata.Reading + "</td></tr>\
<tr><th>" + lan.bt.nginx_writing + "</th><td>" + rdata.Writing + "</td></tr>\
<tr><th>" + lan.bt.nginx_waiting + "</th><td>" + rdata.Waiting + "</td></tr>\
</table></div>";
$(".soft-man-con").html(con);
})
}
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/bt_install.pl
openrestyDir=${serverPath}/source/openresty
Install_openresty()
{
mkdir -p ${openrestyDir}
echo '正在安装脚本文件...' > $install_tmp
if [ ! -f ${openrestyDir}/openresty-1.11.2.5.tar.gz ];then
wget -O ${openrestyDir}/openresty-1.11.2.5.tar.gz https://openresty.org/download/openresty-1.11.2.5.tar.gz
fi
cd ${openrestyDir} && tar -zxvf openresty-1.11.2.5.tar.gz
cd ${openrestyDir}/openresty-1.11.2.5 && ./configure --prefix=$serverPath/openresty \
--with-http_v2_module \
--with-openssl=$serverPath/source/lib/openssl-1.0.2q \
--with-http_stub_status_module && make && make install && \
echo '1.11.2' > $serverPath/openresty/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_openresty()
{
rm -rf $serverPath/openresty
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_openresty
else
Uninstall_openresty
fi
+7 -5
View File
@@ -19,12 +19,16 @@ Install_openresty()
if [ ! -f ${openrestyDir}/openresty-1.13.6.2.tar.gz ];then
wget -O ${openrestyDir}/openresty-1.13.6.2.tar.gz https://openresty.org/download/openresty-1.13.6.2.tar.gz
fi
cd ${openrestyDir} && tar -zxvf openresty-1.13.6.2.tar.gz
cd ${openrestyDir}/openresty* && ./configure --prefix=$serverPath/openresty \
--with-openssl=$serverPath/source/lib/openssl-1.0.2q && make && make install
cd ${openrestyDir}/openresty-1.13.6.2 && ./configure --prefix=$serverPath/openresty \
--with-http_v2_module \
--with-openssl=$serverPath/source/lib/openssl-1.0.2q \
--with-http_stub_status_module \
&& make && make install && \
echo '1.13.6' > $serverPath/openresty/version.pl
echo '安装完成' > $install_tmp
}
@@ -33,9 +37,7 @@ Uninstall_openresty()
rm -rf $serverPath/openresty
echo '卸载完成' > $install_tmp
}
action=$1
host=$2
if [ "${1}" == 'install' ];then
Install_openresty
else
+8
View File
@@ -0,0 +1,8 @@
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
fastcgi_index index.php;
include fastcgi.conf;
include pathinfo.conf;
}
+8
View File
@@ -0,0 +1,8 @@
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
+5
View File
@@ -0,0 +1,5 @@
[global]
include={$SERVER_PATH}/php/{$PHP_VERSION}/etc/php-fpm.d/*.conf
;php_value[auto_prepend_file]={$SERVER_PATH}/md_start.php
;php_value[auto_append_file]={$SERVER_PATH}/md_end.php
+219
View File
@@ -0,0 +1,219 @@
[PHP]
engine = On
short_open_tag = On
asp_tags = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
zend.enable_gc = On
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = On
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_tmp_dir = "/tmp"
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
disable_functions = phpinfo,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
[CLI Server]
cli_server.color = On
[Date]
date.timezone = PRC
[filter]
[iconv]
iconv.input_encoding = ISO-8859-1
iconv.internal_encoding = ISO-8859-1
iconv.output_encoding = ISO-8859-1
[intl]
[sqlite]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.save_path = "/tmp/session"
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatibility_mode = Off
mssql.secure_connection = Off
[Assertion]
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[mcrypt]
[dba]
[curl]
[Zend Opcache]
;[xhprof]
;extension=md_xhprof.so
;xhprof.output_dir="MD:/bin/tmp/xhprof"
+236
View File
@@ -0,0 +1,236 @@
[PHP]
engine = On
short_open_tag = On
asp_tags = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
zend.enable_gc = On
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_tmp_dir = "/tmp/upload"
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
disable_functions = phpinfo,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
[CLI Server]
cli_server.color = On
[Date]
date.timezone = PRC
[filter]
[iconv]
iconv.input_encoding = ISO-8859-1
iconv.internal_encoding = ISO-8859-1
iconv.output_encoding = ISO-8859-1
[intl]
[sqlite]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.save_path = "/tmp/session"
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatibility_mode = Off
mssql.secure_connection = Off
[Assertion]
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[mcrypt]
[dba]
[curl]
[Zend Opcache]
;[xhprof]
;extension=md_xhprof.so
;xhprof.output_dir="MD:/bin/tmp/xhprof"
;extension=igbinary.so
;extension=iconv.so
;extension=yaf.so
;extension=swoole.so
;extension=curl.so
;extension=bcmath.so
;extension=mcrypt.so
;extension=gd.so
;extension=openssl.so
;extension=intl.so
;extension=gettext.so
;extension=imagick.so
;extension=redis.so
;extension=mongodb.so
;extension=memcached.so
;extension=phalcon.so
;extension=opencv.so
+5
View File
@@ -0,0 +1,5 @@
location /phpfpm_status_{$PHP_VERSION} {
fastcgi_pass unix:/tmp/php-cgi-{$PHP_VERSION}.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME \$fastcgi_script_name;
}
+4
View File
@@ -0,0 +1,4 @@
location /{$PHP_VERSION} {
root {$ROOT_PATH}/phpinfo;
include enable-php-{$PHP_VERSION}.conf;
}
+16
View File
@@ -0,0 +1,16 @@
[www]
user = {$PHP_USER}
group = {$PHP_GROUP}
listen = /tmp/php-cgi-{$PHP_VERSION}.sock
listen.owner = {$PHP_USER}
listen.group = {$PHP_GROUP}
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /phpfpm_status_{$PHP_VERSION}
request_slowlog_timeout = 1
slowlog = {$SERVER_PATH}/php/{$PHP_VERSION}/var/log/www-slow.log
Binary file not shown.

Before

Width:  |  Height:  |  Size: 987 B

After

Width:  |  Height:  |  Size: 786 B

+17 -13
View File
@@ -1,18 +1,19 @@
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="redisService();">服务</p>
<p onclick="redisConfig();">安装扩展</p>
<p onclick="redisConfig();">配置修改</p>
<p onclick="redisConfig();">上传限制</p>
<p onclick="redisStatus();">超时限制</p>
<p onclick="redisStatus();">配置文件</p>
<p onclick="redisStatus();">禁用函数</p>
<p onclick="redisStatus();">性能调整</p>
<p onclick="redisStatus();">负载状况</p>
<p onclick="redisStatus();">FPM日志</p>
<p onclick="redisStatus();">慢日志</p>
<p onclick="redisStatus();">PHPIFNO</p>
<p class="bgw" onclick="pluginService('php', $('.plugin_version').attr('version'));">服务</p>
<p onclick="phpLibConfig($('.plugin_version').attr('version'));">安装扩展</p>
<p onclick="phpSetConfig($('.plugin_version').attr('version'));">配置修改</p>
<p onclick="phpUploadLimitReq($('.plugin_version').attr('version'));">上传限制</p>
<p onclick="phpTimeLimitReq($('.plugin_version').attr('version'));">超时限制</p>
<p onclick="pluginConfig('php', $('.plugin_version').attr('version'));">配置文件</p>
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
<p onclick="getFpmConfig($('.plugin_version').attr('version'));">性能调整</p>
<p onclick="getFpmStatus($('.plugin_version').attr('version'));">负载状况</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
@@ -21,5 +22,8 @@
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=php&f=js/php.js");
$.getScript( "/plugins/file?name=php&f=js/php.js", function(){
pluginService('php', $('.plugin_version').attr('version'));
});
</script>
+589 -59
View File
@@ -4,93 +4,623 @@ import sys
import io
import os
import time
import re
import json
import shutil
reload(sys)
sys.setdefaultencoding('utf8')
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.isAppleSystem():
app_debug = True
def status():
data = public.execShell(
"ps -ef|grep redis |grep -v grep | grep -v python | awk '{print $2}'")
def getPluginName():
return 'php'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, public.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, public.returnJson(True, 'ok'))
def getConf(version):
path = getServerDir() + '/' + version + '/etc/php.ini'
return path
def status(version):
cmd = "ps -ef|grep 'php/" + version + \
"' |grep -v grep | grep -v python | awk '{print $2}'"
data = public.execShell(cmd)
if data[0] == '':
return 'stop'
return 'start'
def start():
path = os.path.dirname(os.getcwd())
cmd = path + "/redis/bin/redis-server"
cmd = cmd + " " + path + "/redis/redis.conf"
data = public.execShell(cmd)
if data[0] == '':
def contentReplace(content, version):
service_path = public.getServerDir()
content = content.replace('{$ROOT_PATH}', public.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$PHP_VERSION}', version)
if public.isAppleSystem():
# user = public.execShell(
# "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
content = content.replace('{$PHP_USER}', 'nobody')
content = content.replace('{$PHP_GROUP}', 'nobody')
rep = 'listen.owner\s*=\s*(.+)\r?\n'
val = ';listen.owner = nobody\n'
content = re.sub(rep, val, content)
rep = 'listen.group\s*=\s*(.+)\r?\n'
val = ';listen.group = nobody\n'
content = re.sub(rep, val, content)
rep = 'user\s*=\s*(.+)\r?\n'
val = ';user = nobody\n'
content = re.sub(rep, val, content)
rep = r'[^\.]group\s*=\s*(.+)\r?\n'
val = ';group = nobody\n'
content = re.sub(rep, val, content)
else:
content = content.replace('{$PHP_USER}', 'www')
content = content.replace('{$PHP_GROUP}', 'www')
return content
def makeOpenrestyConf():
if public.isInstalledWeb():
d_pathinfo = public.getServerDir() + '/openresty/nginx/conf/pathinfo.conf'
if not os.path.exists(d_pathinfo):
s_pathinfo = getPluginDir() + '/conf/pathinfo.conf'
shutil.copyfile(s_pathinfo, d_pathinfo)
info = getPluginDir() + '/info.json'
content = public.readFile(info)
content = json.loads(content)
versions = content['versions']
tpl = getPluginDir() + '/conf/enable-php.conf'
tpl_content = public.readFile(tpl)
for x in range(len(versions)):
desc_file = public.getServerDir() + '/openresty/nginx/conf/enable-php-' + \
versions[x] + '.conf'
if not os.path.exists(desc_file):
w_content = contentReplace(tpl_content, versions[x])
public.writeFile(desc_file, w_content)
def phpFpmReplace(version):
desc_php_fpm = getServerDir() + '/' + version + '/etc/php-fpm.conf'
if not os.path.exists(desc_php_fpm):
tpl_php_fpm = getPluginDir() + '/conf/php-fpm.conf'
content = public.readFile(tpl_php_fpm)
content = contentReplace(content, version)
public.writeFile(desc_php_fpm, content)
def phpFpmWwwReplace(version):
service_php_fpm_dir = getServerDir() + '/' + version + '/etc/php-fpm.d/'
if not os.path.exists(service_php_fpm_dir):
os.mkdir(service_php_fpm_dir)
service_php_fpmwww = service_php_fpm_dir + '/www.conf'
if not os.path.exists(service_php_fpmwww):
tpl_php_fpmwww = getPluginDir() + '/conf/www.conf'
content = public.readFile(tpl_php_fpmwww)
content = contentReplace(content, version)
public.writeFile(service_php_fpmwww, content)
def makePhpIni(version):
d_ini = public.getServerDir() + '/php/' + version + '/etc/php.ini'
if not os.path.exists(d_ini):
s_ini = getPluginDir() + '/conf/php' + version + '.ini'
shutil.copyfile(s_ini, d_ini)
def initReplace(version):
makeOpenrestyConf()
makePhpIni(version)
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/php' + version
if not os.path.exists(file_bin):
file_tpl = getPluginDir() + '/init.d/php.tpl'
content = public.readFile(file_tpl)
content = contentReplace(content, version)
public.writeFile(file_bin, content)
public.execShell('chmod +x ' + file_bin)
phpFpmWwwReplace(version)
phpFpmReplace(version)
session_path = '/tmp/session'
if not os.path.exists(session_path):
os.mkdir(session_path)
if not public.isAppleSystem():
public.execShell('chmod -R www:www' + session_path)
return file_bin
def phpOp(version, method):
file = initReplace(version)
data = public.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return 'fail'
return data[1]
def stop():
data = public.execShell(
"ps -ef|grep redis |grep -v grep |grep -v python |awk '{print $2}' | xargs kill -9")
if data[0] == '':
return 'ok'
return 'fail'
def start(version):
return phpOp(version, 'start')
def restart():
return 'ok'
def stop(version):
return phpOp(version, 'stop')
def reload():
return 'ok'
def restart(version):
return phpOp(version, 'restart')
def runInfo():
path = os.path.dirname(os.getcwd())
cmd = path + "/redis/bin/redis-cli info"
data = public.execShell(cmd)[0]
res = [
'tcp_port',
'uptime_in_days', # 已运行天数
'connected_clients', # 连接的客户端数量
'used_memory', # Redis已分配的内存总量
'used_memory_rss', # Redis占用的系统内存总量
'used_memory_peak', # Redis所用内存的高峰值
'mem_fragmentation_ratio', # 内存碎片比率
'total_connections_received', # 运行以来连接过的客户端的总数量
'total_commands_processed', # 运行以来执行过的命令的总数量
'instantaneous_ops_per_sec', # 服务器每秒钟执行的命令数量
'keyspace_hits', # 查找数据库键成功的次数
'keyspace_misses', # 查找数据库键失败的次数
'latest_fork_usec' # 最近一次 fork() 操作耗费的毫秒数
def reload(version):
return phpOp(version, 'reload')
def fpmLog(version):
return getServerDir() + '/' + version + '/var/log/php-fpm.log'
def fpmSlowLog(version):
return getServerDir() + '/' + version + '/var/log/www-slow.log'
def getPhpConf(version):
gets = [
{'name': 'short_open_tag', 'type': 1, 'ps': '短标签支持'},
{'name': 'asp_tags', 'type': 1, 'ps': 'ASP标签支持'},
{'name': 'max_execution_time', 'type': 2, 'ps': '最大脚本运行时间'},
{'name': 'max_input_time', 'type': 2, 'ps': '最大输入时间'},
{'name': 'memory_limit', 'type': 2, 'ps': '脚本内存限制'},
{'name': 'post_max_size', 'type': 2, 'ps': 'POST数据最大尺寸'},
{'name': 'file_uploads', 'type': 1, 'ps': '是否允许上传文件'},
{'name': 'upload_max_filesize', 'type': 2, 'ps': '允许上传文件的最大尺寸'},
{'name': 'max_file_uploads', 'type': 2, 'ps': '允许同时上传文件的最大数量'},
{'name': 'default_socket_timeout', 'type': 2, 'ps': 'Socket超时时间'},
{'name': 'error_reporting', 'type': 3, 'ps': '错误级别'},
{'name': 'display_errors', 'type': 1, 'ps': '是否输出详细错误信息'},
{'name': 'cgi.fix_pathinfo', 'type': 0, 'ps': '是否开启pathinfo'},
{'name': 'date.timezone', 'type': 3, 'ps': '时区'}
]
data = data.split("\n")
result = {}
for d in data:
if len(d) < 3:
phpini = public.readFile(getServerDir() + '/' + version + '/etc/php.ini')
result = []
for g in gets:
rep = g['name'] + '\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
tmp = re.search(rep, phpini)
if not tmp:
continue
t = d.strip().split(':')
if not t[0] in res:
continue
result[t[0]] = t[1]
g['value'] = tmp.groups()[0]
result.append(g)
return public.getJson(result)
def getConf():
path = os.path.dirname(os.getcwd()) + "/redis/redis.conf"
return path
def submitPhpConf(version):
gets = ['display_errors', 'cgi.fix_pathinfo', 'date.timezone', 'short_open_tag',
'asp_tags', 'max_execution_time', 'max_input_time', 'memory_limit',
'post_max_size', 'file_uploads', 'upload_max_filesize', 'max_file_uploads',
'default_socket_timeout', 'error_reporting']
args = getArgs()
filename = getServerDir() + '/' + version + '/etc/php.ini'
phpini = public.readFile(filename)
for g in gets:
if g in args:
rep = g + '\s*=\s*(.+)\r?\n'
val = g + ' = ' + args[g] + '\n'
phpini = re.sub(rep, val, phpini)
public.writeFile(filename, phpini)
public.execShell(getServerDir() + '/init.d/php' + version + ' reload')
return public.returnJson(True, '设置成功')
def getLimitConf(version):
fileini = getServerDir() + "/" + version + "/etc/php.ini"
phpini = public.readFile(fileini)
filefpm = getServerDir() + "/" + version + "/etc/php-fpm.conf"
phpfpm = public.readFile(filefpm)
# print fileini, filefpm
data = {}
try:
rep = "upload_max_filesize\s*=\s*([0-9]+)M"
tmp = re.search(rep, phpini).groups()
data['max'] = tmp[0]
except:
data['max'] = '50'
try:
rep = "request_terminate_timeout\s*=\s*([0-9]+)\n"
tmp = re.search(rep, phpfpm).groups()
data['maxTime'] = tmp[0]
except:
data['maxTime'] = 0
try:
rep = r"\n;*\s*cgi\.fix_pathinfo\s*=\s*([0-9]+)\s*\n"
tmp = re.search(rep, phpini).groups()
if tmp[0] == '1':
data['pathinfo'] = True
else:
data['pathinfo'] = False
except:
data['pathinfo'] = False
return public.getJson(data)
def setMaxTime(version):
args = getArgs()
data = checkArgs(args, ['time'])
if not data[0]:
return data[1]
time = args['time']
if int(time) < 30 or int(time) > 86400:
return public.returnJson(False, '请填写30-86400间的值!')
filefpm = getServerDir() + "/" + version + "/etc/php-fpm.conf"
conf = public.readFile(filefpm)
rep = "request_terminate_timeout\s*=\s*([0-9]+)\n"
conf = re.sub(rep, "request_terminate_timeout = " + time + "\n", conf)
public.writeFile(filefpm, conf)
fileini = getServerDir() + "/" + version + "/etc/php.ini"
phpini = public.readFile(fileini)
rep = "max_execution_time\s*=\s*([0-9]+)\r?\n"
phpini = re.sub(rep, "max_execution_time = " + time + "\n", phpini)
rep = "max_input_time\s*=\s*([0-9]+)\r?\n"
phpini = re.sub(rep, "max_input_time = " + time + "\n", phpini)
public.writeFile(fileini, phpini)
return public.returnJson(True, '设置成功!')
def setMaxSize(version):
args = getArgs()
if not 'max' in args:
return 'missing time args!'
max = args['max']
if int(max) < 2:
return public.returnJson(False, '上传大小限制不能小于2MB!')
path = getServerDir() + '/' + version + '/etc/php.ini'
conf = public.readFile(path)
rep = u"\nupload_max_filesize\s*=\s*[0-9]+M"
conf = re.sub(rep, u'\nupload_max_filesize = ' + max + 'M', conf)
rep = u"\npost_max_size\s*=\s*[0-9]+M"
conf = re.sub(rep, u'\npost_max_size = ' + max + 'M', conf)
public.writeFile(path, conf)
# if public.get_webserver() == 'nginx':
# path = web.ctx.session.setupPath + '/nginx/conf/nginx.conf'
# conf = public.readFile(path)
# rep = "client_max_body_size\s+([0-9]+)m"
# tmp = re.search(rep, conf).groups()
# if int(tmp[0]) < int(max):
# conf = re.sub(rep, 'client_max_body_size ' + max + 'm', conf)
# public.writeFile(path, conf)
public.writeLog("TYPE_PHP", "PHP_UPLOAD_MAX", (version, max))
return public.returnJson(True, '设置成功!')
def getFpmConfig(version):
filefpm = getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf'
conf = public.readFile(filefpm)
data = {}
rep = "\s*pm.max_children\s*=\s*([0-9]+)\s*"
tmp = re.search(rep, conf).groups()
data['max_children'] = tmp[0]
rep = "\s*pm.start_servers\s*=\s*([0-9]+)\s*"
tmp = re.search(rep, conf).groups()
data['start_servers'] = tmp[0]
rep = "\s*pm.min_spare_servers\s*=\s*([0-9]+)\s*"
tmp = re.search(rep, conf).groups()
data['min_spare_servers'] = tmp[0]
rep = "\s*pm.max_spare_servers \s*=\s*([0-9]+)\s*"
tmp = re.search(rep, conf).groups()
data['max_spare_servers'] = tmp[0]
rep = "\s*pm\s*=\s*(\w+)\s*"
tmp = re.search(rep, conf).groups()
data['pm'] = tmp[0]
return public.getJson(data)
def setFpmConfig(version):
args = getArgs()
# if not 'max' in args:
# return 'missing time args!'
version = args['version']
max_children = args['max_children']
start_servers = args['start_servers']
min_spare_servers = args['min_spare_servers']
max_spare_servers = args['max_spare_servers']
pm = args['pm']
file = getServerDir() + '/' + version + '/etc/php-fpm.d/www.conf'
conf = public.readFile(file)
rep = "\s*pm.max_children\s*=\s*([0-9]+)\s*"
conf = re.sub(rep, "\npm.max_children = " + max_children, conf)
rep = "\s*pm.start_servers\s*=\s*([0-9]+)\s*"
conf = re.sub(rep, "\npm.start_servers = " + start_servers, conf)
rep = "\s*pm.min_spare_servers\s*=\s*([0-9]+)\s*"
conf = re.sub(rep, "\npm.min_spare_servers = " +
min_spare_servers, conf)
rep = "\s*pm.max_spare_servers \s*=\s*([0-9]+)\s*"
conf = re.sub(rep, "\npm.max_spare_servers = " +
max_spare_servers + "\n", conf)
rep = "\s*pm\s*=\s*(\w+)\s*"
conf = re.sub(rep, "\npm = " + pm + "\n", conf)
public.writeFile(file, conf)
reload(version)
public.writeLog("TYPE_PHP", 'PHP_CHILDREN', (version, max_children,
start_servers, min_spare_servers, max_spare_servers))
return public.returnJson(True, '设置成功')
def checkFpmStatusFile(version):
if public.isInstalledWeb():
desc_file = public.getServerDir(
) + '/openresty/nginx/conf/php_status/phpfpm_status_' + version + '.conf'
if not os.path.exists(desc_file):
tpl = getPluginDir() + '/conf/phpfpm_status.conf'
content = public.readFile(tpl)
content = contentReplace(content, version)
public.writeFile(desc_file, content)
public.restartWeb()
def getFpmStatus(version):
checkFpmStatusFile(version)
result = public.httpGet(
'http://127.0.0.1/phpfpm_status_' + version + '?json')
tmp = json.loads(result)
fTime = time.localtime(int(tmp['start time']))
tmp['start time'] = time.strftime('%Y-%m-%d %H:%M:%S', fTime)
return public.getJson(tmp)
def getDisableFunc(version):
filename = public.getServerDir() + '/php/' + version + '/etc/php.ini'
if not os.path.exists(filename):
return public.returnJson(False, '指定PHP版本不存在!')
phpini = public.readFile(filename)
data = {}
rep = "disable_functions\s*=\s{0,1}(.*)\n"
tmp = re.search(rep, phpini).groups()
data['disable_functions'] = tmp[0]
return public.getJson(data)
def setDisableFunc(version):
filename = public.getServerDir() + '/php/' + version + '/etc/php.ini'
if not os.path.exists(filename):
return public.returnJson(False, '指定PHP版本不存在!')
args = getArgs()
disable_functions = args['disable_functions']
phpini = public.readFile(filename)
rep = "disable_functions\s*=\s*.*\n"
phpini = re.sub(rep, 'disable_functions = ' +
disable_functions + "\n", phpini)
public.writeLog('TYPE_PHP', 'PHP_DISABLE_FUNCTION',
(version, disable_functions))
public.writeFile(filename, phpini)
reload(version)
return public.returnJson(True, '设置成功!')
def checkPhpinfoFile(version):
if public.isInstalledWeb():
desc_file = public.getServerDir(
) + '/openresty/nginx/conf/php_status/phpinfo_' + version + '.conf'
if not os.path.exists(desc_file):
tpl = getPluginDir() + '/conf/phpinfo.conf'
content = public.readFile(tpl)
content = contentReplace(content, version)
public.writeFile(desc_file, content)
public.restartWeb()
def getPhpinfo(version):
checkPhpinfoFile(version)
sPath = public.getRootDir() + '/phpinfo/' + version
# public.execShell("rm -rf " + public.getRootDir() + '/phpinfo')
public.execShell("mkdir -p " + sPath)
public.writeFile(sPath + '/phpinfo.php', '<?php phpinfo(); ?>')
# print 'http://127.0.0.1/' + version + '/phpinfo.php'
phpinfo = public.httpGet('http://127.0.0.1/' + version + '/phpinfo.php', 3)
# os.system("rm -rf " + public.getRootDir() + '/phpinfo')
return phpinfo
def getLibConf(version):
fname = public.getServerDir() + '/php/' + version + '/etc/php.ini'
if not os.path.exists(fname):
return public.returnJson(False, '指定PHP版本不存在!')
phpini = public.readFile(fname)
libpath = getPluginDir() + '/versions/phplib.conf'
phplib = json.loads(public.readFile(libpath))
libs = []
tasks = public.M('tasks').where(
"status!=?", ('1',)).field('status,name').select()
for lib in phplib:
lib['task'] = '1'
for task in tasks:
tmp = public.getStrBetween('[', ']', task['name'])
if not tmp:
continue
tmp1 = tmp.split('-')
if tmp1[0].lower() == lib['name'].lower():
lib['task'] = task['status']
lib['phpversions'] = []
lib['phpversions'].append(tmp1[1])
if phpini.find(lib['check']) == -1:
lib['status'] = False
else:
lib['status'] = True
libs.append(lib)
return public.returnJson(True, 'OK!', libs)
def installLib(version):
args = getArgs()
data = checkArgs(args, ['name'])
if not data[0]:
return data[1]
name = args['name']
execstr = "cd " + getPluginDir() + '/versions/' + version + " && /bin/bash " + \
name + '.sh' + ' install ' + version
rettime = time.strftime('%Y-%m-%d %H:%M:%S')
insert_info = (None, '安装[' + name + '-' + version + ']',
'execshell', '0', rettime, execstr)
public.M('tasks').add('id,name,type,status,addtime,execstr', insert_info)
return public.returnJson(True, '已将下载任务添加到队列!')
def uninstallLib(version):
args = getArgs()
data = checkArgs(args, ['name'])
if not data[0]:
return data[1]
name = args['name']
execstr = "cd " + getPluginDir() + '/versions/' + version + " && /bin/bash " + \
name + '.sh' + ' uninstall ' + version
rettime = time.strftime('%Y-%m-%d %H:%M:%S')
insert_info = (None, '安装[' + name + '-' + version + ']',
'execshell', '0', rettime, execstr)
public.M('tasks').add('id,name,type,status,addtime,execstr', insert_info)
return public.returnJson(True, '已将卸载载任务添加到队列!')
if __name__ == "__main__":
if len(sys.argv) < 3:
print 'missing parameters'
exit(0)
func = sys.argv[1]
if func == 'run_info':
print runInfo()
elif func == 'conf':
print getConf()
elif func == 'status':
print status()
version = sys.argv[2]
if func == 'status':
print status(version)
elif func == 'start':
print start()
print start(version)
elif func == 'stop':
print stop()
print stop(version)
elif func == 'restart':
print restart()
print restart(version)
elif func == 'reload':
print reload()
print reload(version)
elif func == 'fpm_log':
print fpmLog(version)
elif func == 'fpm_slow_log':
print fpmSlowLog(version)
elif func == 'conf':
print getConf(version)
elif func == 'get_php_conf':
print getPhpConf(version)
elif func == 'submit_php_conf':
print submitPhpConf(version)
elif func == 'get_limit_conf':
print getLimitConf(version)
elif func == 'set_max_time':
print setMaxTime(version)
elif func == 'set_max_size':
print setMaxSize(version)
elif func == 'get_fpm_conf':
print getFpmConfig(version)
elif func == 'set_fpm_conf':
print setFpmConfig(version)
elif func == 'get_fpm_status':
print getFpmStatus(version)
elif func == 'get_disable_func':
print getDisableFunc(version)
elif func == 'set_disable_func':
print setDisableFunc(version)
elif func == 'get_phpinfo':
print getPhpinfo(version)
elif func == 'get_lib_conf':
print getLibConf(version)
elif func == 'install_lib':
print installLib(version)
elif func == 'uninstall_lib':
print uninstallLib(version)
else:
print "fail"
+152
View File
@@ -0,0 +1,152 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: php-fpm
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts php-fpm
# Description: starts the PHP FastCGI Process Manager daemon
### END INIT INFO
prefix={$SERVER_PATH}/php/{$PHP_VERSION}
exec_prefix=${prefix}
php_fpm_BIN=${exec_prefix}/sbin/php-fpm
php_fpm_CONF=${prefix}/etc/php-fpm.conf
php_fpm_PID=${prefix}/var/run/php-fpm.pid
php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"
wait_for_pid () {
try=0
while test $try -lt 35 ; do
case "$1" in
'created')
if [ -f "$2" ] ; then
try=''
break
fi
;;
'removed')
if [ ! -f "$2" ] ; then
try=''
break
fi
;;
esac
echo -n .
try=`expr $try + 1`
sleep 1
done
}
case "$1" in
start)
echo -n "Starting php-fpm "
$php_fpm_BIN --daemonize $php_opts
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
fi
wait_for_pid created $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
stop)
echo -n "Gracefully shutting down php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -QUIT `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed. Use force-quit"
exit 1
else
echo " done"
fi
;;
status)
if [ ! -r $php_fpm_PID ] ; then
echo "php-fpm is stopped"
exit 0
fi
PID=`cat $php_fpm_PID`
if ps -p $PID | grep -q $PID; then
echo "php-fpm (pid $PID) is running..."
else
echo "php-fpm dead but pid file exists"
fi
;;
force-quit)
echo -n "Terminating php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -TERM `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
restart)
$0 stop
$0 start
;;
reload)
echo -n "Reload service php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -USR2 `cat $php_fpm_PID`
echo " done"
;;
*)
echo "Usage: $0 {start|stop|force-quit|restart|reload|status}"
exit 1
;;
esac
+328 -465
View File
@@ -1,115 +1,48 @@
//软件管理
function phpSoftMain(name, key) {
if (!isNaN(name)) {
var nametext = "php" + name;
name = name.replace(".", "");
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function phpPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'php';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
} else {
req_data['args'] = JSON.stringify(args);
}
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.get('/plugins?action=getPluginInfo&name=php', function(rdata) {
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
nameA = rdata.versions[key];
bodys = [
'<p class="bgw pstate" data-id="0"><a href="javascript:service(\'' + name + '\',' + nameA.run + ')">' + lan.soft.php_main1 + '</a><span class="spanmove"></span></p>',
'<p data-id="1"><a id="phpext" href="javascript:SetPHPConfig(\'' + name + '\',' + nameA.pathinfo + ')">' + lan.soft.php_main5 + '</a><span class="spanmove"></span></p>',
'<p data-id="2"><a href="javascript:SetPHPConf(\'' + name + '\')">' + lan.soft.config_edit + '</a><span class="spanmove"></span></p>',
'<p data-id="3"><a href="javascript:phpUploadLimit(\'' + name + '\',' + nameA.max + ')">' + lan.soft.php_main2 + '</a><span class="spanmove"></span></p>',
'<p class="phphide" data-id="4"><a href="javascript:phpTimeLimit(\'' + name + '\',' + nameA.maxTime + ')">' + lan.soft.php_main3 + '</a><span class="spanmove"></span></p>',
'<p data-id="5"><a href="javascript:configChange(\'' + name + '\')">' + lan.soft.php_main4 + '</a><span class="spanmove"></span></p>',
'<p data-id="6"><a href="javascript:disFun(\'' + name + '\')">' + lan.soft.php_main6 + '</a><span class="spanmove"></span></p>',
'<p class="phphide" data-id="7"><a href="javascript:SetFpmConfig(\'' + name + '\')">' + lan.soft.php_main7 + '</a><span class="spanmove"></span></p>',
'<p class="phphide" data-id="8"><a href="javascript:GetPHPStatus(\'' + name + '\')">' + lan.soft.php_main8 + '</a><span class="spanmove"></span></p>',
'<p class="phphide" data-id="9"><a href="javascript:GetFpmLogs(\'' + name + '\')">FPM日志</a><span class="spanmove"></span></p>',
'<p class="phphide" data-id="10"><a href="javascript:GetFpmSlowLogs(\'' + name + '\')">慢日志</a><span class="spanmove"></span></p>',
'<p data-id="11"><a href="javascript:BtPhpinfo(\'' + name + '\')">phpinfo</a><span class="spanmove"></span></p>'
]
var sdata = '';
if (rdata.phpSort == false) {
rdata.phpSort = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
} else {
rdata.phpSort = rdata.phpSort.split('|');
}
for (var i = 0; i < rdata.phpSort.length; i++) {
sdata += bodys[rdata.phpSort[i]];
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.open({
type: 1,
area: '640px',
title: nametext + lan.soft.admin,
closeBtn: 2,
shift: 0,
content: '<div class="bt-w-main" style="width:640px;">\
<input name="softMenuSortOrder" type="hidden" />\
<div class="bt-w-menu soft-man-menu">\
' + sdata + '\
</div>\
<div id="webEdit-con" class="bt-w-con pd15" style="height:555px;overflow:auto">\
<div class="soft-man-con"></div>\
</div>\
</div>'
});
if (name == "52") {
$(".phphide").hide();
if(typeof(callback) == 'function'){
callback(data);
}
if (rdata.versions.length < 5) {
$(".phphide").hide();
$(".pstate").hide();
SetPHPConfig(name, nameA.pathinfo);
$("p[data-id='4']").addClass('bgw');
} else {
service(name, nameA.run);
}
$(".bt-w-menu p a").click(function() {
var txt = $(this).text();
$(this).parent().addClass("bgw").siblings().removeClass("bgw");
if (txt != lan.soft.php_menu_ext) $(".soft-man-con").removeAttr("style");
});
$(".soft-man-menu").dragsort({ dragSelector: ".spanmove", dragEnd: MenusaveOrder });
});
}
//FPM日志
function GetFpmLogs(phpversion) {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.get('/ajax?action=GetFpmLogs&version=' + phpversion, function(logs) {
layer.close(loadT);
if (logs.status !== true) {
logs.msg = '';
}
if (logs.msg == '') logs.msg = '当前没有fpm日志.';
var phpCon = '<textarea readonly="" style="margin: 0px;width: 500px;height: 520px;background-color: #333;color:#fff; padding:0 5px" id="error_log">' + logs.msg + '</textarea>';
$(".soft-man-con").html(phpCon);
var ob = document.getElementById('error_log');
ob.scrollTop = ob.scrollHeight;
});
}
//FPM-Slow日志
function GetFpmSlowLogs(phpversion) {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.get('/ajax?action=GetFpmSlowLogs&version=' + phpversion, function(logs) {
layer.close(loadT);
if (logs.status !== true) {
logs.msg = '';
}
if (logs.msg == '') logs.msg = '当前没有慢日志.';
var phpCon = '<textarea readonly="" style="margin: 0px;width: 500px;height: 520px;background-color: #333;color:#fff; padding:0 5px" id="error_log">' + logs.msg + '</textarea>';
$(".soft-man-con").html(phpCon);
var ob = document.getElementById('error_log');
ob.scrollTop = ob.scrollHeight;
});
},'json');
}
//配置修改
function SetPHPConf(version) {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=GetPHPConf', 'version=' + version, function(rdata) {
layer.close(loadT);
function phpSetConfig(version) {
phpPost('get_php_conf', version,'',function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var mlist = '';
for (var i = 0; i < rdata.length; i++) {
var w = '70'
@@ -130,16 +63,16 @@ function SetPHPConf(version) {
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
}
var phpCon = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right"><button class="btn btn-success btn-sm mr5" onclick="SetPHPConf(' + version + ')">' + lan.public.fresh + '</button><button class="btn btn-success btn-sm" onclick="SubmitPHPConf(' + version + ')">' + lan.public.save + '</button></div>\
</div>'
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right"><button class="btn btn-success btn-sm mr5" onclick="phpSetConfig(' + version + ')">刷新</button><button class="btn btn-success btn-sm" onclick="submitConf(' + version + ')">保存</button></div>\
</div>'
$(".soft-man-con").html(phpCon);
});
}
//提交PHP配置
function SubmitPHPConf(version) {
function submitConf(version) {
var data = {
version: version,
display_errors: $("select[name='display_errors']").val(),
@@ -157,357 +90,96 @@ function SubmitPHPConf(version) {
max_file_uploads: $("input[name='max_file_uploads']").val(),
default_socket_timeout: $("input[name='default_socket_timeout']").val(),
error_reporting: $("input[name='error_reporting']").val() || 'On'
}
};
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=SetPHPConf', data, function(rdata) {
layer.close(loadT);
phpPost('submit_php_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
// console.log(rdata);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//php上传限制
function phpUploadLimitReq(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpUploadLimit(version,rdata['max']);
});
}
function phpUploadLimit(version,max){
var LimitCon = '<p class="conf_p"><input class="phpUploadLimit bt-input-text mr5" type="number" value="'+
max+'" name="max">MB<button class="btn btn-success btn-sm" onclick="setPHPMaxSize(\''+
version+'\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
}
//php超时限制
function phpTimeLimitReq(version){
phpPost('get_limit_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
phpTimeLimit(version,rdata['maxTime']);
});
}
function phpTimeLimit(version, max) {
var LimitCon = '<p class="conf_p"><input class="phpTimeLimit bt-input-text mr5" type="number" value="' + max + '">' + lan.bt.s + '<button class="btn btn-success btn-sm" onclick="SetPHPMaxTime(\'' + version + '\')" style="margin-left:20px">' + lan.public.save + '</button></p>';
var LimitCon = '<p class="conf_p"><input class="phpTimeLimit bt-input-text mr5" type="number" value="' + max + '">秒<button class="btn btn-success btn-sm" onclick="setPHPMaxTime(\'' + version + '\')" style="margin-left:20px">保存</button></p>';
$(".soft-man-con").html(LimitCon);
}
//设置超时限制
function SetPHPMaxTime(version) {
function setPHPMaxTime(version) {
var max = $(".phpTimeLimit").val();
var loadT = layer.msg(lan.soft.the_save, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=setPHPMaxTime', 'version=' + version + '&time=' + max, function(rdata) {
$(".bt-w-menu .active").attr('onclick', "phpTimeLimit('" + version + "'," + max + ")");
$(".bt-w-menu .active a").attr('href', "javascript:phpTimeLimit('" + version + "'," + max + ");");
layer.close(loadT);
phpPost('set_max_time',version,{'time':max},function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//设置PHP上传限制
function SetPHPMaxSize(version) {
function setPHPMaxSize(version) {
max = $(".phpUploadLimit").val();
if (max < 2) {
alert(max);
layer.msg(lan.soft.php_upload_size, { icon: 2 });
layer.msg('上传大小限制不能小于2M', { icon: 2 });
return;
}
var loadT = layer.msg(lan.soft.the_save, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=setPHPMaxSize', '&version=' + version + '&max=' + max, function(rdata) {
$(".bt-w-menu .active").attr('onclick', "phpUploadLimit('" + version + "'," + max + ")");
$(".bt-w-menu .active a").attr('href', "javascript:phpUploadLimit('" + version + "'," + max + ");");
layer.close(loadT);
phpPost('set_max_size',version,{'max':max},function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
})
}
//配置修改
function configChange(type) {
var con = '<p style="color: #666; margin-bottom: 7px">' + lan.bt.edit_ps + '</p><textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
<button id="OnlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">' + lan.public.save + '</button>\
<ul class="help-info-text c7 ptb15">\
<li>' + lan.get('config_edit_ps', [type]) + '</li>\
</ul>';
$(".soft-man-con").html(con);
var fileName = '';
switch (type) {
case 'mysqld':
fileName = '/etc/my.cnf';
break;
case 'nginx':
fileName = '/www/server/nginx/conf/nginx.conf';
break;
case 'pure-ftpd':
fileName = '/www/server/pure-ftpd/etc/pure-ftpd.conf';
break;
case 'apache':
fileName = '/www/server/apache/conf/httpd.conf';
break;
case 'tomcat':
fileName = '/www/server/tomcat/conf/server.xml';
break;
case 'memcached':
fileName = '/etc/init.d/memcached';
break;
case 'redis':
fileName = '/www/server/redis/redis.conf';
break;
default:
fileName = '/www/server/php/' + type + '/etc/php.ini';
break;
}
var loadT = layer.msg(lan.soft.get, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/files?action=GetFileBody', 'path=' + fileName, function(rdata) {
layer.close(loadT);
$("#textBody").empty().text(rdata.data);
$(".CodeMirror").remove();
var editor = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: { "Ctrl-Space": "autocomplete" },
lineNumbers: true,
matchBrackets: true,
});
editor.focus();
$(".CodeMirror-scroll").css({ "height": "300px", "margin": 0, "padding": 0 });
$("#OnlineEditFileBtn").click(function() {
$("#textBody").text(editor.getValue());
confSafe(fileName);
});
});
}
//设置PATHINFO
function SetPathInfo(version, type) {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=setPathInfo', 'version=' + version + '&type=' + type, function(rdata) {
var pathinfo = (type == 'on') ? true : false;
var pathinfoOpt = '<a style="color:red;" href="javascript:SetPathInfo(\'' + version + '\',\'off\');">' + lan.public.off + '</a>'
if (!pathinfo) {
pathinfoOpt = '<a class="link" href="javascript:SetPathInfo(\'' + version + '\',\'on\');">' + lan.public.on + '</a>'
}
var pathinfo1 = '<td>PATH_INFO</td><td>' + lan.soft.php_menu_ext + '</td><td>' + lan.soft.mvc_ps + '</td><td><span class="ico-' + (pathinfo ? 'start' : 'stop') + ' glyphicon glyphicon-' + (pathinfo ? 'ok' : 'remove') + '"></span></td><td style="text-align: right;" width="50">' + pathinfoOpt + '</td>';
$("#pathInfo").html(pathinfo1);
$(".bt-w-menu .bgw").attr('onclick', "SetPHPConfig('" + version + "'," + pathinfo + ",1)");
$(".bt-w-menu .bgw a").attr('href', "javascript:SetPHPConfig('" + version + "'," + pathinfo + ",1);");
layer.msg(rdata.msg, { icon: 1 });
});
}
//PHP扩展配置
function SetPHPConfig(version, pathinfo, go) {
$.get('/ajax?action=GetPHPConfig&version=' + version, function(rdata) {
var body = ""
var opt = ""
for (var i = 0; i < rdata.libs.length; i++) {
if (rdata.libs[i].versions.indexOf(version) == -1) continue;
if (rdata.libs[i]['task'] == '-1' && rdata.libs[i].phpversions.indexOf(version) != -1) {
opt = '<a style="color:green;" href="javascript:messagebox();">' + lan.soft.the_install + '</a>'
} else if (rdata.libs[i]['task'] == '0' && rdata.libs[i].phpversions.indexOf(version) != -1) {
opt = '<a style="color:#C0C0C0;" href="javascript:messagebox();">' + lan.soft.sleep_install + '</a>'
} else if (rdata.libs[i].status) {
opt = '<a style="color:red;" href="javascript:UninstallPHPLib(\'' + version + '\',\'' + rdata.libs[i].name + '\',\'' + rdata.libs[i].title + '\',' + pathinfo + ');">' + lan.soft.uninstall + '</a>'
} else {
opt = '<a class="btlink" href="javascript:InstallPHPLib(\'' + version + '\',\'' + rdata.libs[i].name + '\',\'' + rdata.libs[i].title + '\',' + pathinfo + ');">' + lan.soft.install + '</a>'
}
body += '<tr>' +
'<td>' + rdata.libs[i].name + '</td>' +
'<td>' + rdata.libs[i].type + '</td>' +
'<td>' + rdata.libs[i].msg + '</td>' +
'<td><span class="ico-' + (rdata.libs[i].status ? 'start' : 'stop') + ' glyphicon glyphicon-' + (rdata.libs[i].status ? 'ok' : 'remove') + '"></span></td>' +
'<td style="text-align: right;">' + opt + '</td>' +
'</tr>'
}
var pathinfoOpt = '<a style="color:red;" href="javascript:SetPathInfo(\'' + version + '\',\'off\');">' + lan.soft.off + '</a>'
if (!rdata.pathinfo) {
pathinfoOpt = '<a class="btlink" href="javascript:SetPathInfo(\'' + version + '\',\'on\');">' + lan.soft.on + '</a>'
}
var pathinfo1 = '<tr id="pathInfo"><td>PATH_INFO</td><td>' + lan.soft.php_menu_ext + '</td><td>' + lan.soft.mvc_ps + '</td><td><span class="ico-' + (rdata.pathinfo ? 'start' : 'stop') + ' glyphicon glyphicon-' + (rdata.pathinfo ? 'ok' : 'remove') + '"></span></td><td style="text-align: right;" width="50">' + pathinfoOpt + '</td></tr>';
var con = '<div class="divtable" id="phpextdiv" style="margin-right:10px;height: 420px; overflow: auto; margin-right: 0px;">' +
'<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">' +
'<thead>' +
'<tr>' +
'<th>' + lan.soft.php_ext_name + '</th>' +
'<th width="64">' + lan.soft.php_ext_type + '</th>' +
'<th>' + lan.soft.php_ext_ps + '</th>' +
'<th width="40">' + lan.soft.php_ext_status + '</th>' +
'<th style="text-align: right;" width="50">' + lan.public.action + '</th>' +
'</tr>' +
'</thead>' +
'<tbody>' + pathinfo1 + body + '</tbody>' +
'</table>' +
'</div>' +
'<ul class="help-info-text c7 pull-left"><li>请按实际需求安装扩展,不要安装不必要的PHP扩展,这会影响PHP执行效率,甚至出现异常</li><li>Redis扩展只允许在1个PHP版本中使用,安装到其它PHP版本请在[软件管理]重装Redis</li><li>opcache/xcache/apc等脚本缓存扩展,请只安装其中1个,否则可能导致您的站点程序异常</li></ul>';
var divObj = document.getElementById('phpextdiv');
var scrollTopNum = 0;
if (divObj) scrollTopNum = divObj.scrollTop;
$(".soft-man-con").html(con);
document.getElementById('phpextdiv').scrollTop = scrollTopNum;
});
if (go == undefined) {
setTimeout(function() {
if ($(".bgw #phpext").html() != '安装扩展') {
return;
}
SetPHPConfig(version, pathinfo);
}, 3000);
}
}
//安装扩展
function InstallPHPLib(version, name, title, pathinfo) {
layer.confirm(lan.soft.php_ext_install_confirm.replace('{1}', name), { icon: 3, closeBtn: 2 }, function() {
name = name.toLowerCase();
var data = "name=" + name + "&version=" + version + "&type=1";
var loadT = layer.msg(lan.soft.add_install, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/files?action=InstallSoft', data, function(rdata) {
setTimeout(function() {
layer.close(loadT);
SetPHPConfig(version, pathinfo, true);
setTimeout(function() {
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
}, 1000);
}, 1000);
});
fly("bi-btn");
InstallTips();
GetTaskCount();
});
}
//卸载扩展
function UninstallPHPLib(version, name, title, pathinfo) {
layer.confirm(lan.soft.php_ext_uninstall_confirm.replace('{1}', name), { icon: 3, closeBtn: 2 }, function() {
name = name.toLowerCase();
var data = 'name=' + name + '&version=' + version;
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/files?action=UninstallSoft', data, function(rdata) {
layer.close(loadT);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
SetPHPConfig(version, pathinfo, true);
});
});
}
//禁用函数
function disFun(version) {
$.get('/ajax?action=GetPHPConfig&version=' + version, function(rdata) {
var disable_functions = rdata.disable_functions.split(',');
var dbody = ''
for (var i = 0; i < disable_functions.length; i++) {
if (disable_functions[i] == '') continue;
dbody += "<tr><td>" + disable_functions[i] + "</td><td><a style='float:right;' href=\"javascript:disable_functions('" + version + "','" + disable_functions[i] + "','" + rdata.disable_functions + "');\">" + lan.public.del + "</a></td></tr>";
}
var con = "<div class='dirBinding'>" +
"<input class='bt-input-text mr5' type='text' placeholder='" + lan.soft.fun_ps1 + "' id='disable_function_val' style='height: 28px; border-radius: 3px;width: 410px;' />" +
"<button class='btn btn-success btn-sm' onclick=\"disable_functions('" + version + "',1,'" + rdata.disable_functions + "')\">" + lan.public.add + "</button>" +
"</div>" +
"<div class='divtable mtb15' style='height:350px;overflow:auto'><table class='table table-hover' width='100%' style='margin-bottom:0'>" +
"<thead><tr><th>" + lan.soft.php_ext_name + "</th><th width='100' class='text-right'>" + lan.public.action + "</th></tr></thead>" +
"<tbody id='blacktable'>" + dbody + "</tbody>" +
"</table></div>";
con += '\
<ul class="help-info-text">\
<li>' + lan.soft.fun_ps2 + '</li>\
<li>' + lan.soft.fun_ps3 + '</li>\
</ul>';
$(".soft-man-con").html(con);
});
}
//设置禁用函数
function disable_functions(version, act, fs) {
var fsArr = fs.split(',');
if (act == 1) {
var functions = $("#disable_function_val").val();
for (var i = 0; i < fsArr.length; i++) {
if (functions == fsArr[i]) {
layer.msg(lan.soft.fun_msg, { icon: 5 });
return;
}
}
fs += ',' + functions;
msg = lan.public.add_success;
} else {
fs = '';
for (var i = 0; i < fsArr.length; i++) {
if (act == fsArr[i]) continue;
fs += fsArr[i] + ','
}
msg = lan.public.del_success;
fs = fs.substr(0, fs.length - 1);
}
var data = 'version=' + version + '&disable_functions=' + fs;
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=setPHPDisable', data, function(rdata) {
layer.close(loadT);
layer.msg(rdata.status ? msg : rdata.msg, { icon: rdata.status ? 1 : 2 });
disFun(version);
});
}
//性能调整
function SetFpmConfig(version, action) {
if (action == 1) {
$.post('/system?action=GetMemInfo', '', function(memInfo) {
var limit_children = parseInt(memInfo['memTotal'] / 8);
var max_children = Number($("input[name='max_children']").val());
var start_servers = Number($("input[name='start_servers']").val());
var min_spare_servers = Number($("input[name='min_spare_servers']").val());
var max_spare_servers = Number($("input[name='max_spare_servers']").val());
var pm = $("select[name='pm']").val();
if (limit_children < max_children) {
layer.msg('当前服务器内存不足,最大允许[' + limit_children + ']个子进程!', { icon: 2 });
$("input[name='max_children']").focus();
return;
}
if (max_children < max_spare_servers) {
layer.msg(lan.soft.php_fpm_err1, { icon: 2 });
return;
}
if (min_spare_servers > start_servers) {
layer.msg(lan.soft.php_fpm_err2, { icon: 2 });
return;
}
if (max_spare_servers < min_spare_servers) {
layer.msg(lan.soft.php_fpm_err3, { icon: 2 });
return;
}
if (max_children < start_servers) {
layer.msg(lan.soft.php_fpm_err4, { icon: 2 });
return;
}
if (max_children < 1 || start_servers < 1 || min_spare_servers < 1 || max_spare_servers < 1) {
layer.msg(lan.soft.php_fpm_err5, { icon: 2 });
return;
}
var data = 'version=' + version + '&max_children=' + max_children + '&start_servers=' + start_servers + '&min_spare_servers=' + min_spare_servers + '&max_spare_servers=' + max_spare_servers + '&pm=' + pm;
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=setFpmConfig', data, function(rdata) {
layer.close(loadT);
var loadT = layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
}).error(function() {
layer.close(loadT);
layer.msg(lan.public.config_ok, { icon: 1 });
});
});
return;
}
$.post('/config?action=getFpmConfig', 'version=' + version, function(rdata) {
var limitList = "<option value='0'>" + lan.soft.concurrency_m + "</option>" +
"<option value='1' " + (rdata.max_children == 30 ? 'selected' : '') + ">30" + lan.soft.concurrency + "</option>" +
"<option value='2' " + (rdata.max_children == 50 ? 'selected' : '') + ">50" + lan.soft.concurrency + "</option>" +
"<option value='3' " + (rdata.max_children == 100 ? 'selected' : '') + ">100" + lan.soft.concurrency + "</option>" +
"<option value='4' " + (rdata.max_children == 200 ? 'selected' : '') + ">200" + lan.soft.concurrency + "</option>" +
"<option value='5' " + (rdata.max_children == 300 ? 'selected' : '') + ">300" + lan.soft.concurrency + "</option>" +
"<option value='6' " + (rdata.max_children == 500 ? 'selected' : '') + ">500" + lan.soft.concurrency + "</option>"
var pms = [{ 'name': 'static', 'title': lan.bt.static }, { 'name': 'dynamic', 'title': lan.bt.dynamic }];
function getFpmConfig(version){
phpPost('get_fpm_conf', version, {}, function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var limitList = "<option value='0'>自定义</option>" +
"<option value='1' " + (rdata.max_children == 30 ? 'selected' : '') + ">30并发</option>" +
"<option value='2' " + (rdata.max_children == 50 ? 'selected' : '') + ">50并发</option>" +
"<option value='3' " + (rdata.max_children == 100 ? 'selected' : '') + ">100并发</option>" +
"<option value='4' " + (rdata.max_children == 200 ? 'selected' : '') + ">200并发</option>" +
"<option value='5' " + (rdata.max_children == 300 ? 'selected' : '') + ">300并发</option>" +
"<option value='6' " + (rdata.max_children == 500 ? 'selected' : '') + ">500并发</option>"
var pms = [{ 'name': 'static', 'title': '静态' }, { 'name': 'dynamic', 'title': '动态' }];
var pmList = '';
for (var i = 0; i < pms.length; i++) {
pmList += '<option value="' + pms[i].name + '" ' + ((pms[i].name == rdata.pm) ? 'selected' : '') + '>' + pms[i].title + '</option>';
}
var body = "<div class='bingfa'>" +
"<p class='line'><span class='span_tit'>" + lan.soft.concurrency_type + ":</span><select class='bt-input-text' name='limit' style='width:100px;'>" + limitList + "</select></p>" +
"<p class='line'><span class='span_tit'>" + lan.soft.php_fpm_model + ":</span><select class='bt-input-text' name='pm' style='width:100px;'>" + pmList + "</select><span class='c9'>*" + lan.soft.php_fpm_ps1 + "</span></p>" +
"<p class='line'><span class='span_tit'>max_children:</span><input class='bt-input-text' type='number' name='max_children' value='" + rdata.max_children + "' /><span class='c9'>*" + lan.soft.php_fpm_ps2 + "</span></p>" +
"<p class='line'><span class='span_tit'>start_servers:</span><input class='bt-input-text' type='number' name='start_servers' value='" + rdata.start_servers + "' /> <span class='c9'>*" + lan.soft.php_fpm_ps3 + "</span></p>" +
"<p class='line'><span class='span_tit'>min_spare_servers:</span><input class='bt-input-text' type='number' name='min_spare_servers' value='" + rdata.min_spare_servers + "' /> <span class='c9'>*" + lan.soft.php_fpm_ps4 + "</span></p>" +
"<p class='line'><span class='span_tit'>max_spare_servers:</span><input class='bt-input-text' type='number' name='max_spare_servers' value='" + rdata.max_spare_servers + "' /> <span class='c9'>*" + lan.soft.php_fpm_ps5 + "</span></p>" +
"<div class='mtb15'><button class='btn btn-success btn-sm' onclick='SetFpmConfig(\"" + version + "\",1)'>" + lan.public.save + "</button></div>" +
"</div>"
"<p class='line'><span class='span_tit'>并发方案:</span><select class='bt-input-text' name='limit' style='width:100px;'>" + limitList + "</select></p>" +
"<p class='line'><span class='span_tit'>运行模式:</span><select class='bt-input-text' name='pm' style='width:100px;'>" + pmList + "</select><span class='c9'>*PHP-FPM运行模式</span></p>" +
"<p class='line'><span class='span_tit'>max_children:</span><input class='bt-input-text' type='number' name='max_children' value='" + rdata.max_children + "' /><span class='c9'>*允许创建的最大子进程数</span></p>" +
"<p class='line'><span class='span_tit'>start_servers:</span><input class='bt-input-text' type='number' name='start_servers' value='" + rdata.start_servers + "' /> <span class='c9'>*起始进程数(服务启动后初始进程数量)</span></p>" +
"<p class='line'><span class='span_tit'>min_spare_servers:</span><input class='bt-input-text' type='number' name='min_spare_servers' value='" + rdata.min_spare_servers + "' /> <span class='c9'>*最小空闲进程数(清理空闲进程后的保留数量)</span></p>" +
"<p class='line'><span class='span_tit'>max_spare_servers:</span><input class='bt-input-text' type='number' name='max_spare_servers' value='" + rdata.max_spare_servers + "' /> <span class='c9'>*最大空闲进程数(当空闲进程达到此值时清理)</span></p>" +
"<div class='mtb15'><button class='btn btn-success btn-sm' onclick='setFpmConfig(\"" + version + "\",1)'>保存</button></div>" +
"</div>";
$(".soft-man-con").html(body);
$("select[name='limit']").change(function() {
@@ -563,54 +235,245 @@ function SetFpmConfig(version, action) {
});
}
//phpinfo
function BtPhpinfo(version) {
var con = '<button class="btn btn-default btn-sm" onclick="GetPHPInfo(\'' + version + '\')">' + lan.soft.phpinfo + '</button>';
$(".soft-man-con").html(con);
}
//获取PHPInfo
function GetPHPInfo(version) {
var loadT = layer.msg(lan.soft.get, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.get('/ajax?action=GetPHPInfo&version=' + version, function(rdata) {
layer.close(loadT);
layer.open({
type: 1,
title: "PHP-" + version + "-PHPINFO",
area: ['70%', '90%'],
closeBtn: 2,
shadeClose: true,
content: rdata.replace('a:link {color: #009; text-decoration: none; background-color: #fff;}', '').replace('a:link {color: #000099; text-decoration: none; background-color: #ffffff;}', '')
});
function setFpmConfig(version){
var max_children = Number($("input[name='max_children']").val());
var start_servers = Number($("input[name='start_servers']").val());
var min_spare_servers = Number($("input[name='min_spare_servers']").val());
var max_spare_servers = Number($("input[name='max_spare_servers']").val());
var pm = $("select[name='pm']").val();
if (max_children < max_spare_servers) {
layer.msg('max_spare_servers 不能大于 max_children', { icon: 2 });
return;
}
if (min_spare_servers > start_servers) {
layer.msg('min_spare_servers 不能大于 start_servers', { icon: 2 });
return;
}
if (max_spare_servers < min_spare_servers) {
layer.msg('min_spare_servers 不能大于 max_spare_servers', { icon: 2 });
return;
}
if (max_children < start_servers) {
layer.msg('start_servers 不能大于 max_children', { icon: 2 });
return;
}
if (max_children < 1 || start_servers < 1 || min_spare_servers < 1 || max_spare_servers < 1) {
layer.msg('配置值不能小于1', { icon: 2 });
return;
}
var data = {
version:version,
max_children:max_children,
start_servers:start_servers,
min_spare_servers:min_spare_servers,
max_spare_servers:max_spare_servers,
pm:pm,
};
phpPost('set_fpm_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//查看PHP负载状态
function GetPHPStatus(version) {
$.post('/ajax?action=GetPHPStatus', 'version=' + version, function(rdata) {
function getFpmStatus(version){
phpPost('get_fpm_status', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
var con = "<div style='height:420px;overflow:hidden;'><table class='table table-hover table-bordered GetPHPStatus' style='margin:0;padding:0'>\
<tr><th>" + lan.bt.php_pool + "</th><td>" + rdata.pool + "</td></tr>\
<tr><th>" + lan.bt.php_manager + "</th><td>" + ((rdata['process manager'] == 'dynamic') ? lan.bt.dynamic : lan.bt.static) + "</td></tr>\
<tr><th>" + lan.bt.php_start + "</th><td>" + rdata['start time'] + "</td></tr>\
<tr><th>" + lan.bt.php_accepted + "</th><td>" + rdata['accepted conn'] + "</td></tr>\
<tr><th>" + lan.bt.php_queue + "</th><td>" + rdata['listen queue'] + "</td></tr>\
<tr><th>" + lan.bt.php_max_queue + "</th><td>" + rdata['max listen queue'] + "</td></tr>\
<tr><th>" + lan.bt.php_len_queue + "</th><td>" + rdata['listen queue len'] + "</td></tr>\
<tr><th>" + lan.bt.php_idle + "</th><td>" + rdata['idle processes'] + "</td></tr>\
<tr><th>" + lan.bt.php_active + "</th><td>" + rdata['active processes'] + "</td></tr>\
<tr><th>" + lan.bt.php_total + "</th><td>" + rdata['total processes'] + "</td></tr>\
<tr><th>" + lan.bt.php_max_active + "</th><td>" + rdata['max active processes'] + "</td></tr>\
<tr><th>" + lan.bt.php_max_children + "</th><td>" + rdata['max children reached'] + "</td></tr>\
<tr><th>" + lan.bt.php_slow + "</th><td>" + rdata['slow requests'] + "</td></tr>\
</table></div>";
<tr><th>应用池(pool)</th><td>" + rdata.pool + "</td></tr>\
<tr><th>进程管理方式(process manager)</th><td>" + ((rdata['process manager'] == 'dynamic') ? '动态' : '静态') + "</td></tr>\
<tr><th>启动日期(start time)</th><td>" + rdata['start time'] + "</td></tr>\
<tr><th>请求数(accepted conn)</th><td>" + rdata['accepted conn'] + "</td></tr>\
<tr><th>请求队列(listen queue)</th><td>" + rdata['listen queue'] + "</td></tr>\
<tr><th>最大等待队列(max listen queue)</th><td>" + rdata['max listen queue'] + "</td></tr>\
<tr><th>socket队列长度(listen queue len)</th><td>" + rdata['listen queue len'] + "</td></tr>\
<tr><th>空闲进程数量(idle processes)</th><td>" + rdata['idle processes'] + "</td></tr>\
<tr><th>活跃进程数量(active processes)</th><td>" + rdata['active processes'] + "</td></tr>\
<tr><th>总进程数量(total processes)</th><td>" + rdata['total processes'] + "</td></tr>\
<tr><th>最大活跃进程数量(max active processes)</th><td>" + rdata['max active processes'] + "</td></tr>\
<tr><th>到达进程上限次数(max children reached)</th><td>" + rdata['max children reached'] + "</td></tr>\
<tr><th>慢请求数量(slow requests)</th><td>" + rdata['slow requests'] + "</td></tr>\
</table></div>";
$(".soft-man-con").html(con);
$(".GetPHPStatus td,.GetPHPStatus th").css("padding", "7px");
})
});
}
//禁用函数
function disableFunc(version) {
phpPost('get_disable_func', version,'',function(data){
var rdata = $.parseJSON(data.data);
var disable_functions = rdata.disable_functions.split(',');
var dbody = ''
for (var i = 0; i < disable_functions.length; i++) {
if (disable_functions[i] == '') continue;
dbody += "<tr><td>" + disable_functions[i] + "</td><td><a style='float:right;' href=\"javascript:setDisableFunc('" + version + "','" + disable_functions[i] + "','" + rdata.disable_functions + "');\">删除</a></td></tr>";
}
var con = "<div class='dirBinding'>" +
"<input class='bt-input-text mr5' type='text' placeholder='添加要被禁止的函数名,如: exec' id='disable_function_val' style='height: 28px; border-radius: 3px;width: 410px;' />" +
"<button class='btn btn-success btn-sm' onclick=\"setDisableFunc('" + version + "',1,'" + rdata.disable_functions + "')\">添加</button>" +
"</div>" +
"<div class='divtable mtb15' style='height:350px;overflow:auto'><table class='table table-hover' width='100%' style='margin-bottom:0'>" +
"<thead><tr><th>名称</th><th width='100' class='text-right'>操作</th></tr></thead>" +
"<tbody id='blacktable'>" + dbody + "</tbody>" +
"</table></div>";
con += '<ul class="help-info-text">\
<li>在此处可以禁用指定函数的调用,以增强环境安全性!</li>\
<li>强烈建议禁用如exec,system等危险函数!</li>\
</ul>';
$(".soft-man-con").html(con);
});
}
//设置禁用函数
function setDisableFunc(version, act, fs) {
var fsArr = fs.split(',');
if (act == 1) {
var functions = $("#disable_function_val").val();
for (var i = 0; i < fsArr.length; i++) {
if (functions == fsArr[i]) {
layer.msg(lan.soft.fun_msg, { icon: 5 });
return;
}
}
fs += ',' + functions;
msg = '添加成功';
} else {
fs = '';
for (var i = 0; i < fsArr.length; i++) {
if (act == fsArr[i]) continue;
fs += fsArr[i] + ','
}
msg = '删除成功';
fs = fs.substr(0, fs.length - 1);
}
var data = {
'version':version,
'disable_functions':fs,
};
phpPost('set_disable_func', version,data,function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.status ? msg : rdata.msg, function(){
disableFunc(version);
} ,{ icon: rdata.status ? 1 : 2 });
});
}
//php上传限制
function phpUploadLimit(version, max) {
var LimitCon = '<p class="conf_p"><input class="phpUploadLimit bt-input-text mr5" type="number" value="' + max + '" name="max">MB<button class="btn btn-success btn-sm" onclick="SetPHPMaxSize(\'' + version + '\')" style="margin-left:20px">' + lan.public.save + '</button></p>';
$(".soft-man-con").html(LimitCon);
//phpinfo
function getPhpinfo(version) {
var con = '<button class="btn btn-default btn-sm" onclick="getPHPInfo(\'' + version + '\')">' + lan.soft.phpinfo + '</button>';
$(".soft-man-con").html(con);
}
//获取PHPInfo
function getPHPInfo(version) {
phpPost('get_phpinfo', version, '', function(data){
var rdata = data.data;
layer.open({
type: 1,
title: "PHP-" + version + "-PHPINFO",
area: ['90%', '90%'],
closeBtn: 2,
shadeClose: true,
content: rdata
});
});
}
function phpLibConfig(version){
phpPost('get_lib_conf', version, '', function(data){
var rdata = $.parseJSON(data.data);
var libs = rdata.data;
var body = '';
var opt = '';
for (var i = 0; i < libs.length; i++) {
if (libs[i].versions.indexOf(version) == -1){
continue;
}
if (libs[i]['task'] == '-1' && libs[i].phpversions.indexOf(version) != -1) {
opt = '<a style="color:green;" href="javascript:messageBox();">安装</a>'
} else if (libs[i]['task'] == '0' && libs[i].phpversions.indexOf(version) != -1) {
opt = '<a style="color:#C0C0C0;" href="javascript:messageBox();">等待安装...</a>'
} else if (libs[i].status) {
opt = '<a style="color:red;" href="javascript:uninstallPHPLib(\'' + version + '\',\'' + libs[i].name + '\',\'' + libs[i].title + '\',' + '' + ');">卸载</a>'
} else {
opt = '<a class="btlink" href="javascript:installPHPLib(\'' + version + '\',\'' + libs[i].name + '\',\'' + libs[i].title + '\',' + '' + ');">安装</a>'
}
body += '<tr>' +
'<td>' + libs[i].name + '</td>' +
'<td>' + libs[i].type + '</td>' +
'<td>' + libs[i].msg + '</td>' +
'<td><span class="ico-' + (libs[i].status ? 'start' : 'stop') + ' glyphicon glyphicon-' + (libs[i].status ? 'ok' : 'remove') + '"></span></td>' +
'<td style="text-align: right;">' + opt + '</td>' +
'</tr>';
}
var con = '<div class="divtable" id="phpextdiv" style="margin-right:10px;height: 420px; overflow: auto; margin-right: 0px;">' +
'<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">' +
'<thead>' +
'<tr>' +
'<th>名称</th>' +
'<th width="64">类型</th>' +
'<th>说明</th>' +
'<th width="40">状态</th>' +
'<th style="text-align: right;" width="50">操作</th>' +
'</tr>' +
'</thead>' +
'<tbody>' + body + '</tbody>' +
'</table>' +
'</div>' +
'<ul class="help-info-text c7 pull-left">\
<li>请按实际需求安装扩展,不要安装不必要的PHP扩展,这会影响PHP执行效率,甚至出现异常</li>\
<li>Redis扩展只允许在1个PHP版本中使用,安装到其它PHP版本请在[软件管理]重装Redis</li>\
<li>opcache/xcache/apc等脚本缓存扩展,请只安装其中1个,否则可能导致您的站点程序异常</li>\
</ul>';
$('.soft-man-con').html(con);
});
}
//安装扩展
function installPHPLib(version, name, title, pathinfo) {
layer.confirm('您真的要安装{1}吗?'.replace('{1}', name), { icon: 3, closeBtn: 2 }, function() {
name = name.toLowerCase();
var data = "name=" + name + "&version=" + version + "&type=1";
phpPost('install_lib', version, data, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
getTaskCount();
phpLibConfig(version);
});
});
}
//卸载扩展
function uninstallPHPLib(version, name, title, pathinfo) {
layer.confirm('您真的要安装{1}吗?'.replace('{1}', name), { icon: 3, closeBtn: 2 }, function() {
name = name.toLowerCase();
var data = 'name=' + name + '&version=' + version;
phpPost('uninstall_lib', version, data, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
getTaskCount();
phpLibConfig(version);
});
});
}

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