mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 04:19:26 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26a6a80504 | ||
|
|
498799578a | ||
|
|
6a5b009766 | ||
|
|
8e23411be8 | ||
|
|
b597255d68 | ||
|
|
8979011ec3 | ||
|
|
11a21f9a8b | ||
|
|
1a12f625cd | ||
|
|
11e44d5b0e | ||
|
|
47c1394de6 | ||
|
|
5e7fa28feb | ||
|
|
d04f891ee7 | ||
|
|
3d28e0a3cb | ||
|
|
37112546b9 | ||
|
|
cb719c9973 | ||
|
|
7ec5fe84b2 | ||
|
|
c68cce0198 | ||
|
|
0d7fd11de5 | ||
|
|
643a2e8cf8 | ||
|
|
35ee7d3d10 | ||
|
|
2ce3871ee2 | ||
|
|
812ce86187 | ||
|
|
3d44b3014f | ||
|
|
092494a216 | ||
|
|
a21ad254b7 | ||
|
|
ebd6b9f389 | ||
|
|
33b90a976b | ||
|
|
2518d32019 | ||
|
|
4ded4679f3 | ||
|
|
28d3996d17 | ||
|
|
b76950ed3b | ||
|
|
d49aa168eb | ||
|
|
5304d0b228 | ||
|
|
56e4ef1a4e | ||
|
|
91fc83e0ba | ||
|
|
fc0fdd5772 | ||
|
|
0d0007d9a1 | ||
|
|
a74ace856a | ||
|
|
f46af799a9 | ||
|
|
3e4facbf57 | ||
|
|
ff9466d0a4 | ||
|
|
9cbcff5dbc | ||
|
|
90834415bf | ||
|
|
c2862ab5d4 | ||
|
|
664a7864bc | ||
|
|
9cf6a40493 | ||
|
|
028422337e | ||
|
|
5f10d9433c | ||
|
|
ed49f0b0bd | ||
|
|
090fc0f243 | ||
|
|
f2df81694f | ||
|
|
6cf2e2d6b6 | ||
|
|
defdc3d3b8 | ||
|
|
6d1d1b882e | ||
|
|
54f90c9300 | ||
|
|
a1aa7d465d | ||
|
|
62214c2a88 | ||
|
|
d5a4958566 | ||
|
|
0bca4a3589 | ||
|
|
30bc8b1ec1 | ||
|
|
0472102a3a | ||
|
|
2da863d98a | ||
|
|
88bab4b15b | ||
|
|
d1b4a1cde1 | ||
|
|
d88f6903da | ||
|
|
3a53b360b7 | ||
|
|
3e5b951a41 | ||
|
|
272b6fdeea | ||
|
|
49ac781e87 | ||
|
|
b4f9fa0976 | ||
|
|
96baa99bdc | ||
|
|
5db4f39c76 | ||
|
|
23dadd7f6f | ||
|
|
7d8d48f3d5 | ||
|
|
74fd4bbe08 | ||
|
|
30240443e6 | ||
|
|
e069c3a24e | ||
|
|
73e75abb5f | ||
|
|
b35d516a8e | ||
|
|
aa1875612b | ||
|
|
b189d5b485 | ||
|
|
33b43b253c | ||
|
|
86cfb1b9cf | ||
|
|
f93afb772c | ||
|
|
bd49bd3004 | ||
|
|
db26b09eba | ||
|
|
85da65ad1e | ||
|
|
d9a409ffcc | ||
|
|
ea923a45a6 | ||
|
|
7480cfb5d8 | ||
|
|
be513af18e | ||
|
|
1c5e61a3de | ||
|
|
d26474f222 | ||
|
|
03c796775a | ||
|
|
182d434f84 | ||
|
|
7c1d409e61 | ||
|
|
dab12535f2 | ||
|
|
deffb3d61b | ||
|
|
a4a45f2005 | ||
|
|
32d6a89bd4 | ||
|
|
f41c2454ee | ||
|
|
76dba077c0 | ||
|
|
1c34488abb | ||
|
|
6742d971eb | ||
|
|
3de01da4ba | ||
|
|
4ba526ca2b | ||
|
|
a4e8b6a137 | ||
|
|
50ad3ed7e7 | ||
|
|
64d29659f7 | ||
|
|
2794f49df4 | ||
|
|
3e27f85719 | ||
|
|
a4d70f2294 | ||
|
|
f3cd1f597e | ||
|
|
489c363daf | ||
|
|
77f44481b3 | ||
|
|
fcd4ba024a | ||
|
|
ce6b15939d | ||
|
|
baaccb7960 | ||
|
|
fb559e9f11 | ||
|
|
283a2c052b | ||
|
|
a7bd9e3290 | ||
|
|
b64dbb9aa4 | ||
|
|
d9f63c3a9a | ||
|
|
3c02af41bc | ||
|
|
ac87a6c8b1 | ||
|
|
f19dd2a2b9 | ||
|
|
cef7215fdc | ||
|
|
edb4fc96e1 | ||
|
|
af9f8b73ba | ||
|
|
c85152e85a | ||
|
|
2ee2440c68 | ||
|
|
ecfafc9723 | ||
|
|
dbb4414e65 | ||
|
|
a028e93881 | ||
|
|
475cb5176d | ||
|
|
8b07bd80e6 | ||
|
|
50d26d932f | ||
|
|
22b5ab1179 | ||
|
|
f7c76fb261 | ||
|
|
6531f686ad | ||
|
|
b716f05fb4 | ||
|
|
9a98f1c859 | ||
|
|
e92fc4cfd1 | ||
|
|
da1a76cbef | ||
|
|
fa6b7c21ac | ||
|
|
11748fd33b | ||
|
|
267bbe3865 | ||
|
|
dd27e4b076 | ||
|
|
459229ba15 | ||
|
|
94c5161fde | ||
|
|
5646d1404c | ||
|
|
ef8a10b68d | ||
|
|
c772696f3e | ||
|
|
45faf4e9dd | ||
|
|
5cbca9232c | ||
|
|
742bb6d86d | ||
|
|
b14accd83e | ||
|
|
8ae01d8d36 | ||
|
|
5db1e58e6a | ||
|
|
a2e6d2f280 | ||
|
|
83f3d224ed | ||
|
|
73693620df | ||
|
|
72eb67dfda | ||
|
|
c55b4a02c8 | ||
|
|
721efd6a16 | ||
|
|
61c8ce4b6f | ||
|
|
ce95ca6905 | ||
|
|
01dee5fe1f | ||
|
|
1a72edee9a | ||
|
|
27b6ad0280 | ||
|
|
ae9e6921c3 | ||
|
|
b51eb99027 | ||
|
|
2e584c540d | ||
|
|
bbf258e1a7 | ||
|
|
53d57716aa | ||
|
|
e9a6e5477d | ||
|
|
46ca8a6b44 | ||
|
|
d6f88caf3d | ||
|
|
abc85902a2 | ||
|
|
9edc8bbea2 | ||
|
|
443d3efd37 | ||
|
|
948bcde358 | ||
|
|
83aa3cfca6 | ||
|
|
976c88ed44 | ||
|
|
0db16797b5 | ||
|
|
b7802fc898 | ||
|
|
741dffd5db | ||
|
|
2c9f11bcfe | ||
|
|
16893e51e6 | ||
|
|
34a43a6af9 | ||
|
|
4dd5d946d9 | ||
|
|
7e63f686b9 | ||
|
|
7b57972179 | ||
|
|
a758a36bdc | ||
|
|
84123c603d | ||
|
|
33f9c09a07 |
@@ -1,5 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: midoks
|
||||
|
||||
custom: https://afdian.net/a/mdserver-web
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: BUG提交
|
||||
about: 问题描述
|
||||
---
|
||||
|
||||
## 什么系统 ?
|
||||
|
||||
Debian x, Centos x, Centos x stream, Ubuntu x?
|
||||
|
||||
## 错误信息 ?
|
||||
|
||||
Ex:
|
||||
```bash
|
||||
一个issue,一个问题。多余问题,视情况而答。
|
||||
```
|
||||
|
||||
## 错误截图 ?
|
||||
|
||||
...
|
||||
|
||||
|
||||
## 浏览器版本 ?
|
||||
|
||||
...
|
||||
|
||||
|
||||
## 软件版本(插件/面板) ?
|
||||
|
||||
...
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: 需求提交
|
||||
about: 需求描述
|
||||
---
|
||||
|
||||
## 需求
|
||||
|
||||
想开发一个什么插件?
|
||||
想有什么功能?
|
||||
|
||||
|
||||
## 提供参考
|
||||
|
||||
给开发者提供参考!
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 提出问题
|
||||
url: https://github.com/midoks/mdserver-web/discussions
|
||||
about: 请在讨论中提出问题。
|
||||
- name: 提出建议
|
||||
url: https://github.com/midoks/mdserver-web/discussions/categories/proposal
|
||||
about: 请在讨论中提出建议。
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,3 +0,0 @@
|
||||
### 合并描述
|
||||
|
||||
- 我添加了测试用例来覆盖新代码。
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL55
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL55
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.5
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL56
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL56
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.6
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL57
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL57
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.7
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL80
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL80
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 8.0
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP OpenResty
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "dev" ]
|
||||
pull_request:
|
||||
branches: [ "master", "dev" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install OpenResty
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/openresty && sudo bash install.sh install 1.21.4.1
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,68 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP PHP
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install PHP53
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 53
|
||||
- name: Install PHP54
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 54
|
||||
- name: Install PHP55
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 55
|
||||
- name: Install PHP56
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 56
|
||||
- name: Install PHP70
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 70
|
||||
- name: Install PHP71
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 71
|
||||
- name: Install PHP72
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 72
|
||||
- name: Install PHP73
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 73
|
||||
- name: Install PHP74
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 74
|
||||
- name: Install PHP80
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 80
|
||||
- name: Install PHP81
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 81
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,16 +0,0 @@
|
||||
name: sync2gitee
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
repo-sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mirror the Github organization repos to Gitee.
|
||||
uses: Yikun/hub-mirror-action@master
|
||||
with:
|
||||
src: 'github/midoks'
|
||||
dst: 'gitee/midoks'
|
||||
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
|
||||
dst_token: ${{ secrets.GITEE_TOKEN }}
|
||||
static_list: "mdserver-web"
|
||||
force_update: true
|
||||
+5
-73
@@ -8,11 +8,13 @@ __pycache__/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
@@ -104,77 +106,7 @@ venv.bak/
|
||||
.DS_Store
|
||||
.idea/*.xml
|
||||
.idea/*.iml
|
||||
tmp/*
|
||||
*.swp
|
||||
*.pem
|
||||
*.zip
|
||||
logs/*
|
||||
data/*.db
|
||||
data/iplist.txt
|
||||
tmp/*.pl
|
||||
tmp/*.log
|
||||
data/json/index.json
|
||||
data/json/config.json
|
||||
data/site.pl
|
||||
data/admin_path.pl
|
||||
data/close.pl
|
||||
data/datadir.pl
|
||||
data/502Task.pl
|
||||
data/default.pl
|
||||
data/backup.pl
|
||||
data/debug.pl
|
||||
data/default_site.pl
|
||||
|
||||
ssl/input.pl
|
||||
|
||||
lib/python*
|
||||
|
||||
bin
|
||||
pyvenv.cfg
|
||||
include
|
||||
share
|
||||
pip-selfcheck.json
|
||||
|
||||
scripts/init.d/mw
|
||||
scripts/mdserver-web
|
||||
|
||||
data/api_login.txt
|
||||
data/sessions
|
||||
data/ssl.pl
|
||||
data/port.pl
|
||||
data/ipv6.pl
|
||||
data/restart.pl
|
||||
data/ssl.pl
|
||||
data/edate.pl
|
||||
data/osname.pl
|
||||
data/only_netio_counters.pl
|
||||
data/system.db-journal
|
||||
data/hook_*.json
|
||||
data/letsencrypt.json
|
||||
data/basic_auth.json
|
||||
data/notify.json
|
||||
data/api.json
|
||||
data/bind_domain.pl
|
||||
data/unauthorized_status.pl
|
||||
data/auth_secret.pl
|
||||
|
||||
plugins/vip_*
|
||||
plugins/own_*
|
||||
plugins/my_*
|
||||
plugins/op_auth
|
||||
plugins/l2tp
|
||||
plugins/openlitespeed
|
||||
plugins/tamper_proof
|
||||
plugins/cryptocurrency_trade
|
||||
plugins/mtproxy
|
||||
plugins/zimg
|
||||
plugins/bk_demo
|
||||
plugins/mail
|
||||
plugins/fastdfs
|
||||
plugins/v2ray
|
||||
plugins/frp
|
||||
plugins/file_search
|
||||
plugins/proxysql
|
||||
debug.out
|
||||
|
||||
|
||||
mdioks.session-journal
|
||||
*.session
|
||||
data/system.db
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [midoks] [midoks of copyright owner]
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,213 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/logo.png" height="140" />
|
||||
<h3 align="center">mdserver-web</h3>
|
||||
<p align="center">一款简单Linux面板服务</p>
|
||||
<p align="center">强烈推荐系统:debian</p>
|
||||
</p>
|
||||
# mdweb
|
||||
简单的Linux面板
|
||||
|
||||
### 简介
|
||||
|
||||
简单的Linux面板,感谢BT.CN写出如此好的web管理软件。我一看到,就知道这是我一直想要的页面化管理方式。
|
||||
复制了后台管理界面,按照自己想要的方式写了一版。
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
[](https://github.com/midoks/mdserver-web/wiki)
|
||||
[](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
|
||||
|
||||
* SSH终端工具
|
||||
* 面板收藏功能
|
||||
* 网站子目录绑定
|
||||
* 网站备份功能
|
||||
* 插件方式管理
|
||||
|
||||
基本上可以使用,后续会继续优化!欢迎提供意见!
|
||||
|
||||
- 吹水组 - https://t.me/mdserver_web
|
||||
- 交流论坛 - https://bbs.midoks.icu
|
||||
- discord - https://discord.gg/3zXk4mES
|
||||
### 自动安装
|
||||
```
|
||||
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
|
||||
Talk is cheap, show me the code. -- linus
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | sh
|
||||
```
|
||||
|
||||
- [兼容性测试报告](/compatibility.md)
|
||||
- [常用命令说明](/cmd.md) [ mw default ] [ mw update_dev ]
|
||||
|
||||
### 主要插件介绍
|
||||
|
||||
* OpenResty - 轻量级,占有内存少,并发能力强。
|
||||
* PHP[53-83] - PHP是世界上最好的编程语言。
|
||||
* MySQL - 一种关系数据库管理系统。
|
||||
* MariaDB - 是MySQL的一个重要分支。
|
||||
* MySQL[APT/YUM] - 一种关系数据库管理系统。
|
||||
* MongoDB - 一种非关系NOSQL数据库管理系统。
|
||||
* phpMyAdmin - 著名Web端MySQL管理工具。
|
||||
* Memcached - 一个高性能的分布式内存对象缓存系统。
|
||||
* Redis - 一个高性能的KV数据库。
|
||||
* PureFtpd - 一款专注于程序健壮和软件安全的免费FTP服务器软件。
|
||||
* Gogs - 一款极易搭建的自助Git服务。
|
||||
* Rsyncd - 通用同步服务。
|
||||
|
||||
|
||||
### 插件开发相关
|
||||
|
||||
```
|
||||
插件文档还不完善,如果有不明白的地方提Issue! 我会尽力完善。
|
||||
如果你自己写了插件,想分享出来,也可以提Issue。
|
||||
```
|
||||
|
||||
- 简单例子 - https://github.com/mw-plugin/simple-plugin
|
||||
- 插件地址 - https://github.com/mw-plugin
|
||||
- 开发文档 - https://github.com/midoks/mdserver-web/wiki/插件开发
|
||||
|
||||
## 其他插件
|
||||
|
||||
- OP鉴权 - https://github.com/mw-plugin/op_auth
|
||||
|
||||
|
||||
# Note
|
||||
|
||||
```
|
||||
phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
|
||||
phpMyAdmin[5.2.0]支持MySQL[8.0]
|
||||
|
||||
PHP[53-72]支持phpMyAdmin[4.4.15]
|
||||
PHP[72-83]支持phpMyAdmin[5.2.0]
|
||||
```
|
||||
|
||||
# 郑重声明
|
||||
|
||||
不卖、不会监控(统计使用除外)、更不会注入病毒,大家使用方便(望大家不吝捐赠)。
|
||||
|
||||
- https://www.youtube.com/watch?v=2taa5K-Jmmw
|
||||
|
||||
|
||||
# 特别赞助
|
||||
|
||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan1.cc)
|
||||
|
||||
# AD - VPS推荐 - 🙏
|
||||
|
||||
- [ZZZ评测](https://www.zzzvps.com/)
|
||||
|
||||
| 服务商 | LOGO | 推广地址 | 优惠码 |
|
||||
| ------------- |----------|-----------|-------|
|
||||
| digitalvirt |[](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | mdserver-web |
|
||||
|
||||
# Docker
|
||||
|
||||
- 由[DDS-Derek](https://github.com/DDS-Derek)开发维护。
|
||||
- https://github.com/DDS-Derek/mdserver-web-Docker
|
||||
|
||||
```
|
||||
docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:443 -p 888:888 ddsderek/mw-server:latest
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.16.7
|
||||
|
||||
- mongodb副本设置/备份/认证。
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
- 初始安装
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
|
||||
```
|
||||
|
||||
- 直接更新
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
- 卸载脚本
|
||||
|
||||
```
|
||||
wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
|
||||
```
|
||||
|
||||
### 备用地址
|
||||
|
||||
- 初始安装
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/master/scripts/install.sh | bash
|
||||
```
|
||||
|
||||
- 直接更新
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
- 卸载脚本
|
||||
|
||||
```
|
||||
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
|
||||
```
|
||||
|
||||
|
||||
### 通用软件安装[命令行安装]
|
||||
|
||||
- 需已经安装mdserver-web
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
|
||||
```
|
||||
|
||||
|
||||
### DEV使用
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
|
||||
|
||||
wget --no-check-certificate -O install.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install.sh && bash install.sh
|
||||
|
||||
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
|
||||
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
|
||||
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
|
||||
```
|
||||
|
||||
### 捐赠地址 USDT(TRC20)
|
||||
|
||||
TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
|
||||
|
||||
日行一善,以后必定大富大贵
|
||||
|
||||
|
||||
### 支付宝赞助
|
||||
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/alipay_zz.png)
|
||||
|
||||
|
||||
### 无图不真相
|
||||
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/mdw.jpg)
|
||||
|
||||
|
||||
### Stargazers over time
|
||||
|
||||
[](https://starchart.cc/midoks/mdserver-web)
|
||||
|
||||
|
||||
### 感谢开发赞助
|
||||
|
||||
[](https://digitalvirt.com/aff.php?aff=154)
|
||||
|
||||
### 授权许可
|
||||
|
||||
本项目采用 Apache 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/midoks/mdserver-web/blob/master/LICENSE) 文件中。
|
||||
|
||||
|
||||
@@ -1,52 +1,55 @@
|
||||
# coding:utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 入口文件
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# pip install profiler_online
|
||||
# 性能测试
|
||||
# from profiler_online import run_profiler
|
||||
# run_profiler()
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
from route import app, socketio
|
||||
from datetime import timedelta
|
||||
|
||||
sys.path.append("/class/core/")
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
|
||||
import route
|
||||
from flask import Flask
|
||||
|
||||
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
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)
|
||||
|
||||
try:
|
||||
if __name__ == "__main__":
|
||||
|
||||
PORT = 7200
|
||||
if os.path.exists('data/port.pl'):
|
||||
f = open('data/port.pl')
|
||||
PORT = int(f.read())
|
||||
f.close()
|
||||
|
||||
# HOST = '0.0.0.0'
|
||||
# app.run(host=HOST, port=PORT)
|
||||
|
||||
http_server = WSGIServer(
|
||||
(HOST, PORT), app, handler_class=WebSocketHandler)
|
||||
http_server.serve_forever()
|
||||
socketio.run(app, host=HOST, port=PORT)
|
||||
app.run()
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
print ex
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,146 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 公共操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
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 mw
|
||||
import db
|
||||
|
||||
from flask import redirect
|
||||
|
||||
|
||||
def init():
|
||||
initDB()
|
||||
initUserInfo()
|
||||
initInitD()
|
||||
initInitTask()
|
||||
return True
|
||||
|
||||
|
||||
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 = mw.readFile('data/sql/default.sql')
|
||||
csql_list = csql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
sql.execute(csql_list[index], ())
|
||||
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
|
||||
|
||||
def doContentReplace(src, dst):
|
||||
content = mw.readFile(src)
|
||||
content = content.replace("{$SERVER_PATH}", mw.getRunDir())
|
||||
mw.writeFile(dst, content)
|
||||
|
||||
|
||||
def initInitD():
|
||||
|
||||
# systemctl
|
||||
# sysCfgDir = mw.systemdCfgDir()
|
||||
# if os.path.exists(sysCfgDir) and mw.getOsName() == 'centos' and mw.getOsID() == '9':
|
||||
# systemd_mw = sysCfgDir + '/mw.service'
|
||||
# systemd_mw_task = sysCfgDir + '/mw-task.service'
|
||||
|
||||
# systemd_mw_tpl = mw.getRunDir() + '/scripts/init.d/mw.service.tpl'
|
||||
# systemd_mw_task_tpl = mw.getRunDir() + '/scripts/init.d/mw-task.service.tpl'
|
||||
|
||||
# if os.path.exists(systemd_mw):
|
||||
# os.remove(systemd_mw)
|
||||
# if os.path.exists(systemd_mw_task):
|
||||
# os.remove(systemd_mw_task)
|
||||
|
||||
# doContentReplace(systemd_mw_tpl, systemd_mw)
|
||||
# doContentReplace(systemd_mw_task_tpl, systemd_mw_task)
|
||||
|
||||
# mw.execShell('systemctl enable mw')
|
||||
# mw.execShell('systemctl enable mw-task')
|
||||
# mw.execShell('systemctl daemon-reload')
|
||||
|
||||
script = mw.getRunDir() + '/scripts/init.d/mw.tpl'
|
||||
script_bin = mw.getRunDir() + '/scripts/init.d/mw'
|
||||
doContentReplace(script, script_bin)
|
||||
mw.execShell('chmod +x ' + script_bin)
|
||||
|
||||
# 在linux系统中,确保/etc/init.d存在
|
||||
if not mw.isAppleSystem() and not os.path.exists("/etc/rc.d/init.d"):
|
||||
mw.execShell('mkdir -p /etc/rc.d/init.d')
|
||||
|
||||
if not mw.isAppleSystem() and not os.path.exists("/etc/init.d"):
|
||||
mw.execShell('mkdir -p /etc/init.d')
|
||||
|
||||
# initd
|
||||
if os.path.exists('/etc/rc.d/init.d'):
|
||||
initd_bin = '/etc/rc.d/init.d/mw'
|
||||
if not os.path.exists(initd_bin):
|
||||
import shutil
|
||||
shutil.copyfile(script_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
# 加入自启动
|
||||
mw.execShell('which chkconfig && chkconfig --add mw')
|
||||
|
||||
if os.path.exists('/etc/init.d'):
|
||||
initd_bin = '/etc/init.d/mw'
|
||||
if not os.path.exists(initd_bin):
|
||||
import shutil
|
||||
shutil.copyfile(script_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
# 加入自启动
|
||||
mw.execShell('which update-rc.d && update-rc.d -f mw defaults')
|
||||
|
||||
# 获取系统IPV4
|
||||
mw.setHostAddr(mw.getLocalIp())
|
||||
|
||||
|
||||
def initInitTask():
|
||||
# 创建证书同步命令
|
||||
import cert_api
|
||||
api = cert_api.cert_api()
|
||||
api.createCertCron()
|
||||
|
||||
|
||||
def initUserInfo():
|
||||
|
||||
data = mw.M('users').where('id=?', (1,)).getField('password')
|
||||
if data == '21232f297a57a5a743894a0e4a801fc3':
|
||||
|
||||
pwd = mw.getRandomString(8).lower()
|
||||
file_pw = mw.getRunDir() + '/data/default.pl'
|
||||
mw.writeFile(file_pw, pwd)
|
||||
mw.M('users').where('id=?', (1,)).setField(
|
||||
'password', mw.md5(pwd))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,690 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 计划任务操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
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):
|
||||
p = request.args.get('p', 1)
|
||||
psize = 10
|
||||
|
||||
startPage = (int(p) - 1) * psize
|
||||
pageInfo = str(startPage) + ',' + str(psize)
|
||||
|
||||
_list = mw.M('crontab').where('', ()).field(
|
||||
self.field).limit(pageInfo).order('id desc').select()
|
||||
|
||||
data = []
|
||||
for i in range(len(_list)):
|
||||
tmp = _list[i]
|
||||
if _list[i]['type'] == "day":
|
||||
tmp['type'] = '每天'
|
||||
tmp['cycle'] = mw.getInfo('每天, {1}点{2}分 执行', (str(
|
||||
_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "day-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}天', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.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'] = mw.getInfo(
|
||||
'每小时, 第{1}分钟 执行', (str(_list[i]['where_minute']),))
|
||||
elif _list[i]['type'] == "hour-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}小时', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.getInfo('每{1}小时, 第{2}分钟 执行', (str(
|
||||
_list[i]['where1']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "minute-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}分钟', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.getInfo(
|
||||
'每隔{1}分钟执行', (str(_list[i]['where1']),))
|
||||
elif _list[i]['type'] == "week":
|
||||
tmp['type'] = '每周'
|
||||
if not _list[i]['where1']:
|
||||
_list[i]['where1'] = '0'
|
||||
tmp['cycle'] = mw.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'] = mw.getInfo('每月, {1}日 {2}点{3}分执行', (str(_list[i]['where1']), str(
|
||||
_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
data.append(tmp)
|
||||
|
||||
rdata = {}
|
||||
rdata['data'] = data
|
||||
|
||||
count = mw.M('crontab').where('', ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = p
|
||||
_page['row'] = psize
|
||||
_page['tojs'] = "getCronData"
|
||||
|
||||
rdata['list'] = mw.getPage(_page)
|
||||
rdata['p'] = p
|
||||
|
||||
# backup hook
|
||||
bh_file = mw.getPanelDataDir() + "/hook_backup.json"
|
||||
if os.path.exists(bh_file):
|
||||
hb_data = mw.readFile(bh_file)
|
||||
hb_data = json.loads(hb_data)
|
||||
rdata['backup_hook'] = hb_data
|
||||
|
||||
return mw.getJson(rdata)
|
||||
|
||||
# 设置计划任务状态
|
||||
def setCronStatusApi(self):
|
||||
mid = request.form.get('id', '')
|
||||
cronInfo = mw.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)
|
||||
|
||||
mw.M('crontab').where('id=?', (mid,)).setField('status', status)
|
||||
mw.writeLog(
|
||||
'计划任务', '修改计划任务[' + cronInfo['name'] + ']状态为[' + str(status) + ']')
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
# 获取指定任务数据
|
||||
def getCrondFindApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
data = mw.M('crontab').where(
|
||||
'id=?', (sid,)).field(self.field).find()
|
||||
return mw.getJson(data)
|
||||
|
||||
# 参数校验
|
||||
def cronCheck(self, params):
|
||||
|
||||
if params['stype'] == 'site' or params['stype'] == 'database' or params['stype'].find('database_') > -1 or params['stype'] == 'logs' or params['stype'] == 'path':
|
||||
if params['save'] == '':
|
||||
return False, '保留份数不能为空!'
|
||||
|
||||
if params['type'] == 'day':
|
||||
if params['hour'] == '':
|
||||
return False, '小时不能为空!'
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
if params['type'] == 'day-n':
|
||||
if params['where1'] == '':
|
||||
return False, '天不能为空!'
|
||||
if params['hour'] == '':
|
||||
return False, '小时不能为空!'
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
if params['type'] == 'hour':
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
if params['type'] == 'hour-n':
|
||||
if params['where1'] == '':
|
||||
return False, '小时不能为空!'
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
if params['type'] == 'minute-n':
|
||||
if params['where1'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
if params['type'] == 'week':
|
||||
if params['hour'] == '':
|
||||
return False, '小时不能为空!'
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
if params['type'] == 'month':
|
||||
if params['where1'] == '':
|
||||
return False, '日不能为空!'
|
||||
if params['hour'] == '':
|
||||
return False, '小时不能为空!'
|
||||
if params['minute'] == '':
|
||||
return False, '分钟不能为空!'
|
||||
|
||||
return True, 'OK'
|
||||
|
||||
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 mw.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,
|
||||
}
|
||||
|
||||
is_check_pass, msg = self.cronCheck(params)
|
||||
if not is_check_pass:
|
||||
return mw.returnJson(is_check_pass, msg)
|
||||
|
||||
cuonConfig, get, name = self.getCrondCycle(params)
|
||||
cronInfo = mw.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 = mw.M('crontab').where('id=?', (sid,)).save('name,type,where1,where_hour,where_minute,save,backup_to, sname, sbody,urladdress',
|
||||
(iname, field_type, get['where1'], get['hour'], get['minute'], get['save'], get['backup_to'], sname, get['sbody'], get['urladdress']))
|
||||
self.removeForCrond(cronInfo['echo'])
|
||||
self.syncToCrond(cronInfo)
|
||||
mw.writeLog('计划任务', '修改计划任务[' + cronInfo['name'] + ']成功')
|
||||
return mw.returnJson(True, '修改成功')
|
||||
|
||||
def logsApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
echo = mw.M('crontab').where("id=?", (sid,)).field('echo').find()
|
||||
logFile = mw.getServerDir() + '/cron/' + echo['echo'] + '.log'
|
||||
if not os.path.exists(logFile):
|
||||
return mw.returnJson(False, '当前日志为空!')
|
||||
log = mw.getLastLine(logFile, 500)
|
||||
return mw.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 mw.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,
|
||||
}
|
||||
|
||||
is_check_pass, msg = self.cronCheck(params)
|
||||
if not is_check_pass:
|
||||
return mw.returnJson(is_check_pass, msg)
|
||||
|
||||
addData = self.add(params)
|
||||
if type(addData) == str:
|
||||
return addData
|
||||
|
||||
if addData > 0:
|
||||
return mw.returnJson(True, '添加成功')
|
||||
return mw.returnJson(False, '添加失败')
|
||||
|
||||
def add(self, params):
|
||||
|
||||
iname = params["name"]
|
||||
field_type = params["type"]
|
||||
week = params["week"]
|
||||
where1 = params["where1"]
|
||||
hour = params["hour"]
|
||||
minute = params["minute"]
|
||||
save = params["save"]
|
||||
backup_to = params["backup_to"]
|
||||
stype = params["stype"]
|
||||
sname = params["sname"]
|
||||
sbody = params["sbody"]
|
||||
urladdress = params["urladdress"]
|
||||
|
||||
# print params
|
||||
cronConfig, get, name = self.getCrondCycle(params)
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
cronName = self.getShell(params)
|
||||
|
||||
if type(cronName) == dict:
|
||||
return cronName
|
||||
|
||||
cronConfig += ' ' + cronPath + '/' + cronName + \
|
||||
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
|
||||
|
||||
# print(cronConfig)
|
||||
if not mw.isAppleSystem():
|
||||
wRes = self.writeShell(cronConfig)
|
||||
if type(wRes) != bool:
|
||||
return wRes
|
||||
self.crondReload()
|
||||
|
||||
add_time = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
task_id = mw.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, add_time, 1, save, backup_to, stype, sname, sbody, urladdress,))
|
||||
return task_id
|
||||
|
||||
def startTaskApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
echo = mw.M('crontab').where('id=?', (sid,)).getField('echo')
|
||||
execstr = mw.getServerDir() + '/cron/' + echo
|
||||
os.system('chmod +x ' + execstr)
|
||||
os.system('nohup ' + execstr + ' >> ' + execstr + '.log 2>&1 &')
|
||||
return mw.returnJson(True, '任务已执行!')
|
||||
|
||||
def delApi(self):
|
||||
task_id = request.form.get('id', '')
|
||||
try:
|
||||
data = self.delete(task_id)
|
||||
if not data[0]:
|
||||
return mw.returnJson(False, data[1])
|
||||
return mw.returnJson(True, '删除成功')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '删除失败:' + str(e))
|
||||
|
||||
def delete(self, tid):
|
||||
|
||||
find = mw.M('crontab').where("id=?", (tid,)).field('name,echo').find()
|
||||
if not self.removeForCrond(find['echo']):
|
||||
return (False, '无法写入文件,请检查是否开启了系统加固功能!')
|
||||
|
||||
cronPath = mw.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)
|
||||
|
||||
mw.M('crontab').where("id=?", (tid,)).delete()
|
||||
mw.writeLog('计划任务', mw.getInfo('删除计划任务[{1}]成功!', (find['name'],)))
|
||||
return (True, "OK")
|
||||
|
||||
def delLogsApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
try:
|
||||
echo = mw.M('crontab').where("id=?", (sid,)).getField('echo')
|
||||
logFile = mw.getServerDir() + '/cron/' + echo + '.log'
|
||||
os.remove(logFile)
|
||||
return mw.returnJson(True, '任务日志已清空!')
|
||||
except:
|
||||
return mw.returnJson(False, '任务日志清空失败!')
|
||||
|
||||
# 取数据列表
|
||||
def getDataListApi(self):
|
||||
stype = request.form.get('type', '')
|
||||
|
||||
bak_data = []
|
||||
if stype == 'site' or stype == 'sites' or stype == 'database' or stype.find('database_') > -1 or stype == 'path':
|
||||
hookPath = mw.getPanelDataDir() + "/hook_backup.json"
|
||||
if os.path.exists(hookPath):
|
||||
t = mw.readFile(hookPath)
|
||||
bak_data = json.loads(t)
|
||||
|
||||
if stype == 'database' or stype.find('database_') > -1:
|
||||
sqlite3_name = 'mysql'
|
||||
path = mw.getServerDir() + '/mysql'
|
||||
if stype != 'database':
|
||||
soft_name = stype.replace('database_', '')
|
||||
path = mw.getServerDir() + '/' + soft_name
|
||||
|
||||
if soft_name == 'postgresql':
|
||||
sqlite3_name = 'pgsql'
|
||||
|
||||
if soft_name == 'mongodb':
|
||||
sqlite3_name = 'mongodb'
|
||||
|
||||
db_list = {}
|
||||
db_list['orderOpt'] = bak_data
|
||||
|
||||
if not os.path.exists(path + '/' + sqlite3_name + '.db'):
|
||||
db_list['data'] = []
|
||||
else:
|
||||
db_list['data'] = mw.M('databases').dbPos(path, sqlite3_name).field('name,ps').select()
|
||||
return mw.getJson(db_list)
|
||||
|
||||
if stype == 'path':
|
||||
db_list = {}
|
||||
db_list['data'] = [{"name": mw.getWwwDir(), "ps": "www"}]
|
||||
db_list['orderOpt'] = bak_data
|
||||
return mw.getJson(db_list)
|
||||
|
||||
data = {}
|
||||
data['orderOpt'] = bak_data
|
||||
|
||||
default_db = 'sites'
|
||||
# if stype == 'site' or stype == 'logs':
|
||||
# stype == 'sites'
|
||||
|
||||
data['data'] = mw.M(default_db).field('name,ps').select()
|
||||
return mw.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 = mw.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"
|
||||
|
||||
start_head = '''
|
||||
SCRIPT_RUN_TIME="0s"
|
||||
MW_ToSeconds()
|
||||
{
|
||||
SEC=$1
|
||||
if [ $SEC -lt 60 ]; then
|
||||
SCRIPT_RUN_TIME="${SEC}s"
|
||||
elif [ $SEC -ge 60 ] && [ $SEC -lt 3600 ];then
|
||||
SCRIPT_RUN_TIME="$(( SEC / 60 ))m$(( SEC % 60 ))s"
|
||||
elif [ $SEC -ge 3600 ]; then
|
||||
SCRIPT_RUN_TIME="$(( SEC / 3600 ))h$(( (SEC % 3600) / 60 ))m$(( (SEC % 3600) % 60 ))s"
|
||||
fi
|
||||
}
|
||||
START_MW_SHELL_TIME=`date +%s`
|
||||
'''
|
||||
|
||||
source_bin_activate = '''
|
||||
export LANG=en_US.UTF-8
|
||||
MW_PATH=%s/bin/activate
|
||||
if [ -f $MW_PATH ];then
|
||||
source $MW_PATH
|
||||
fi''' % (mw.getRunDir(),)
|
||||
|
||||
head = head + start_head + source_bin_activate + "\n"
|
||||
log = '.log'
|
||||
|
||||
script_dir = mw.getRunDir() + "/scripts"
|
||||
source_stype = 'database'
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
script_dir = mw.getRunDir() + "/plugins/" + plugin_name + "/scripts"
|
||||
|
||||
source_stype = stype
|
||||
stype = 'database'
|
||||
|
||||
wheres = {
|
||||
'path': head + "python3 " + script_dir + "/backup.py path " + param['sname'] + " " + str(param['save']),
|
||||
'site': head + "python3 " + script_dir + "/backup.py site " + param['sname'] + " " + str(param['save']),
|
||||
'database': head + "python3 " + script_dir + "/backup.py database " + param['sname'] + " " + str(param['save']),
|
||||
'logs': head + "python3 " + script_dir + "/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
|
||||
'rememory': head + "/bin/bash " + script_dir + '/rememory.sh'
|
||||
}
|
||||
if param['backup_to'] != 'localhost':
|
||||
cfile = mw.getPluginDir() + "/" + \
|
||||
param['backup_to'] + "/index.py"
|
||||
|
||||
wheres['path'] = head + "python3 " + cfile + \
|
||||
" path " + param['sname'] + " " + str(param['save'])
|
||||
wheres['site'] = head + "python3 " + cfile + \
|
||||
" site " + param['sname'] + " " + str(param['save'])
|
||||
wheres['database'] = head + "python3 " + cfile + " " + \
|
||||
source_stype + " " + \
|
||||
param['sname'] + " " + str(param['save'])
|
||||
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"`
|
||||
END_MW_SHELL_TIME=`date +"%s"`
|
||||
((SHELL_COS_TIME=($END_MW_SHELL_TIME-$START_MW_SHELL_TIME)))
|
||||
MW_ToSeconds $SHELL_COS_TIME
|
||||
echo "★[$endDate] Successful | Script Run [$SCRIPT_RUN_TIME] "
|
||||
echo "----------------------------------------------------------------------------"
|
||||
'''
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
if not os.path.exists(cronPath):
|
||||
mw.execShell('mkdir -p ' + cronPath)
|
||||
|
||||
if not 'echo' in param:
|
||||
cronName = mw.md5(mw.md5(str(time.time()) + '_mw'))
|
||||
else:
|
||||
cronName = param['echo']
|
||||
file = cronPath + '/' + cronName
|
||||
mw.writeFile(file, self.checkScript(shell))
|
||||
mw.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):
|
||||
file = '/var/spool/cron/crontabs/root'
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
file = '/etc/crontab'
|
||||
elif current_os.startswith("freebsd"):
|
||||
file = '/var/cron/tabs/root'
|
||||
|
||||
if not os.path.exists(file):
|
||||
file = '/var/spool/cron/root'
|
||||
|
||||
if not os.path.exists(file):
|
||||
mw.writeFile(file, '')
|
||||
conf = mw.readFile(file)
|
||||
conf += str(config) + "\n"
|
||||
if mw.writeFile(file, conf):
|
||||
if not os.path.exists(file):
|
||||
mw.execShell("chmod 600 '" + file +
|
||||
"' && chown root.root " + file)
|
||||
else:
|
||||
mw.execShell("chmod 600 '" + file +
|
||||
"' && chown root.crontab " + file)
|
||||
return True
|
||||
return mw.returnJson(False, '文件写入失败,请检查是否开启系统加固功能!')
|
||||
|
||||
# 重载配置
|
||||
def crondReload(self):
|
||||
if mw.isAppleSystem():
|
||||
# mw.execShell('/usr/sbin/cron restart')
|
||||
if os.path.exists('/etc/crontab'):
|
||||
pass
|
||||
else:
|
||||
if os.path.exists('/etc/init.d/crond'):
|
||||
mw.execShell('/etc/init.d/crond reload')
|
||||
elif os.path.exists('/etc/init.d/cron'):
|
||||
mw.execShell('service cron restart')
|
||||
else:
|
||||
mw.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 mw.isAppleSystem():
|
||||
file = '/etc/crontab'
|
||||
|
||||
if not os.path.exists(file):
|
||||
return False
|
||||
else:
|
||||
file = u_file
|
||||
|
||||
if mw.isAppleSystem():
|
||||
return True
|
||||
|
||||
conf = mw.readFile(file)
|
||||
rep = ".+" + str(echo) + ".+\n"
|
||||
conf = re.sub(rep, "", conf)
|
||||
if not mw.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 = mw.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()
|
||||
+35
-155
@@ -1,21 +1,8 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# sqlite3操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class Sql():
|
||||
@@ -27,7 +14,6 @@ class Sql():
|
||||
__DB_TABLE = "" # 被操作的表名称
|
||||
__OPT_WHERE = "" # where条件
|
||||
__OPT_LIMIT = "" # limit条件
|
||||
__OPT_GROUP = "" # group条件
|
||||
__OPT_ORDER = "" # order条件
|
||||
__OPT_FIELD = "*" # field条件
|
||||
__OPT_PARAM = () # where值
|
||||
@@ -35,73 +21,40 @@ class Sql():
|
||||
def __init__(self):
|
||||
self.__DB_FILE = 'data/default.db'
|
||||
|
||||
def __getConn(self):
|
||||
def __GetConn(self):
|
||||
# 取数据库对象
|
||||
try:
|
||||
if self.__DB_CONN == None:
|
||||
self.__DB_CONN = sqlite3.connect(self.__DB_FILE)
|
||||
self.__DB_CONN.text_factory = str
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def autoTextFactory(self):
|
||||
if sys.version_info[0] == 3:
|
||||
self.__DB_CONN.text_factory = lambda x: str(
|
||||
x, encoding="utf-8", errors='ignore')
|
||||
else:
|
||||
self.__DB_CONN.text_factory = lambda x: unicode(
|
||||
x, "utf-8", "ignore")
|
||||
|
||||
def dbfile(self, name):
|
||||
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
|
||||
return self
|
||||
|
||||
def where(self, where, param=()):
|
||||
def where(self, where, param):
|
||||
# WHERE条件
|
||||
if where:
|
||||
self.__OPT_WHERE = " WHERE " + where
|
||||
self.__OPT_PARAM = param
|
||||
return self
|
||||
|
||||
def andWhere(self, where, param):
|
||||
# WHERE条件
|
||||
if where:
|
||||
self.__OPT_WHERE = self.__OPT_WHERE + " and " + where
|
||||
# print(param)
|
||||
# print(self.__OPT_PARAM)
|
||||
self.__OPT_PARAM = self.__OPT_PARAM + param
|
||||
return self
|
||||
|
||||
def order(self, order):
|
||||
# ORDER条件
|
||||
if len(order):
|
||||
self.__OPT_ORDER = " ORDER BY " + order
|
||||
else:
|
||||
self.__OPT_ORDER = ""
|
||||
return self
|
||||
|
||||
def group(self, group):
|
||||
if len(group):
|
||||
self.__OPT_GROUP = " GROUP BY " + group
|
||||
else:
|
||||
self.__OPT_GROUP = ""
|
||||
return self
|
||||
|
||||
def limit(self, limit):
|
||||
# LIMIT条件
|
||||
if len(limit):
|
||||
self.__OPT_LIMIT = " LIMIT " + limit
|
||||
else:
|
||||
self.__OPT_LIMIT = ""
|
||||
return self
|
||||
|
||||
def field(self, field):
|
||||
@@ -112,12 +65,10 @@ class Sql():
|
||||
|
||||
def select(self):
|
||||
# 查询数据集
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
try:
|
||||
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
|
||||
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
# print(sql)
|
||||
# print(self.__OPT_PARAM)
|
||||
self.__OPT_WHERE + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
data = result.fetchall()
|
||||
# 构造字曲系列
|
||||
@@ -141,53 +92,12 @@ class Sql():
|
||||
del(tmp)
|
||||
self.__close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def inquiry(self, input_field=''):
|
||||
# 查询数据集
|
||||
# 不清空查询参数
|
||||
self.__getConn()
|
||||
try:
|
||||
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
|
||||
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
|
||||
if os.path.exists('data/debug.pl'):
|
||||
print(sql, self.__OPT_PARAM)
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
data = result.fetchall()
|
||||
# 构造字曲系列
|
||||
if self.__OPT_FIELD != "*":
|
||||
|
||||
if input_field != "":
|
||||
field = input_field.split(',')
|
||||
else:
|
||||
field = self.__OPT_FIELD.split(',')
|
||||
|
||||
tmp = []
|
||||
for row in data:
|
||||
i = 0
|
||||
tmp1 = {}
|
||||
for key in field:
|
||||
tmp1[key] = row[i]
|
||||
i += 1
|
||||
tmp.append(tmp1)
|
||||
del(tmp1)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
else:
|
||||
# 将元组转换成列表
|
||||
tmp = map(list, data)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
return data
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def getField(self, keyName):
|
||||
# 取回指定字段
|
||||
result = self.field(keyName).select()
|
||||
# print(result)
|
||||
if len(result) == 1:
|
||||
return result[0][keyName]
|
||||
return result
|
||||
@@ -214,7 +124,8 @@ class Sql():
|
||||
|
||||
def add(self, keys, param):
|
||||
# 插入数据
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
self.__DB_CONN.text_factory = str
|
||||
try:
|
||||
values = ""
|
||||
for key in keys.split(','):
|
||||
@@ -223,36 +134,13 @@ class Sql():
|
||||
sql = "INSERT INTO " + self.__DB_TABLE + \
|
||||
"(" + keys + ") " + "VALUES(" + values + ")"
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
last_id = result.lastrowid
|
||||
id = result.lastrowid
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return last_id
|
||||
except Exception as ex:
|
||||
return id
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
# 插入数据
|
||||
def insert(self, pdata):
|
||||
if not pdata:
|
||||
return False
|
||||
keys, param = self.__format_pdata(pdata)
|
||||
return self.add(keys, param)
|
||||
|
||||
# 更新数据
|
||||
def update(self, pdata):
|
||||
if not pdata:
|
||||
return False
|
||||
keys, param = self.__format_pdata(pdata)
|
||||
return self.save(keys, param)
|
||||
|
||||
# 构造数据
|
||||
def __format_pdata(self, pdata):
|
||||
keys = pdata.keys()
|
||||
keys_str = ','.join(keys)
|
||||
param = []
|
||||
for k in keys:
|
||||
param.append(pdata[k])
|
||||
return keys_str, tuple(param)
|
||||
|
||||
def checkInput(self, data):
|
||||
if not data:
|
||||
return data
|
||||
@@ -273,7 +161,8 @@ class Sql():
|
||||
|
||||
def addAll(self, keys, param):
|
||||
# 插入数据
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
self.__DB_CONN.text_factory = str
|
||||
try:
|
||||
values = ""
|
||||
for key in keys.split(','):
|
||||
@@ -283,7 +172,7 @@ class Sql():
|
||||
"(" + keys + ") " + "VALUES(" + values + ")"
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
return True
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def commit(self):
|
||||
@@ -292,7 +181,8 @@ class Sql():
|
||||
|
||||
def save(self, keys, param):
|
||||
# 更新数据
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
self.__DB_CONN.text_factory = str
|
||||
try:
|
||||
opt = ""
|
||||
for key in keys.split(','):
|
||||
@@ -300,8 +190,8 @@ class Sql():
|
||||
opt = opt[0:len(opt) - 1]
|
||||
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt + self.__OPT_WHERE
|
||||
|
||||
# import mw
|
||||
# mw.writeFile('/tmp/test.pl', sql)
|
||||
import public
|
||||
public.writeFile('/tmp/test.pl', sql)
|
||||
|
||||
# 处理拼接WHERE与UPDATE参数
|
||||
tmp = list(param)
|
||||
@@ -312,12 +202,12 @@ class Sql():
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def delete(self, id=None):
|
||||
# 删除数据
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
try:
|
||||
if id:
|
||||
self.__OPT_WHERE = " WHERE id=?"
|
||||
@@ -327,54 +217,44 @@ class Sql():
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def originExecute(self, sql, param=()):
|
||||
self.__getConn()
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
self.__DB_CONN.commit()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def execute(self, sql, param=()):
|
||||
def execute(self, sql, param):
|
||||
# 执行SQL语句返回受影响行
|
||||
self.__getConn()
|
||||
# print sql, param
|
||||
self.__GetConn()
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def query(self, sql, param=()):
|
||||
def query(self, sql, param):
|
||||
# 执行SQL语句返回数据集
|
||||
self.__getConn()
|
||||
self.__GetConn()
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
# 将元组转换成列表
|
||||
# data = map(list, result)
|
||||
return result
|
||||
except Exception as ex:
|
||||
data = map(list, result)
|
||||
return data
|
||||
except Exception, ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def create(self, name):
|
||||
# 创建数据表
|
||||
self.__getConn()
|
||||
import mw
|
||||
script = mw.readFile('data/' + name + '.sql')
|
||||
self.__GetConn()
|
||||
import public
|
||||
script = public.readFile('data/' + name + '.sql')
|
||||
result = self.__DB_CONN.executescript(script)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
|
||||
def fofile(self, filename):
|
||||
# 执行脚本
|
||||
self.__getConn()
|
||||
import mw
|
||||
script = mw.readFile(filename)
|
||||
self.__GetConn()
|
||||
import public
|
||||
script = public.readFile(filename)
|
||||
result = self.__DB_CONN.executescript(script)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,513 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 防火墙操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class firewall_api:
|
||||
|
||||
__isFirewalld = False
|
||||
__isIptables = False
|
||||
__isUfw = False
|
||||
__isMac = False
|
||||
|
||||
def __init__(self):
|
||||
iptables_file = mw.systemdCfgDir() + '/iptables.service'
|
||||
if os.path.exists('/usr/sbin/firewalld'):
|
||||
self.__isFirewalld = True
|
||||
elif os.path.exists('/usr/sbin/ufw'):
|
||||
self.__isUfw = True
|
||||
elif os.path.exists(iptables_file):
|
||||
self.__isIptables = True
|
||||
elif mw.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 mw.returnJson(False, '您输入的IP地址不合法!')
|
||||
address = port
|
||||
if mw.M('firewall').where("port=?", (address,)).count() > 0:
|
||||
return mw.returnJson(False, '您要放屏蔽的IP已存在屏蔽列表,无需重复处理!')
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw deny from ' + address + ' to any')
|
||||
else:
|
||||
if self.__isIptables:
|
||||
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
|
||||
mw.execShell(cmd)
|
||||
elif self.__isFirewalld:
|
||||
cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \
|
||||
address + '" drop\''
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
pass
|
||||
|
||||
msg = mw.getInfo('屏蔽IP[{1}]成功!', (address,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,ps,addtime', (address, ps, addtime))
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
# 添加放行端口
|
||||
def addAcceptPortApi(self):
|
||||
if not self.getFwStatus():
|
||||
return mw.returnJson(False, '防火墙启动时,才能添加规则!')
|
||||
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
stype = request.form.get('type', '').strip()
|
||||
protocol = request.form.get('protocol', '').strip()
|
||||
|
||||
data = self.addAcceptPortArgs(port, ps, stype, protocol)
|
||||
return mw.getJson(data)
|
||||
|
||||
# 添加放行端口
|
||||
def addAcceptPortArgs(self, port, ps, stype, protocol='tcp'):
|
||||
import re
|
||||
import time
|
||||
|
||||
if not self.getFwStatus():
|
||||
self.setFw(0)
|
||||
|
||||
rep = "^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep, port):
|
||||
return mw.returnData(False, '端口范围不正确!')
|
||||
|
||||
if mw.M('firewall').where("port=?", (port,)).count() > 0:
|
||||
return mw.returnData(False, '您要放行的端口已存在,无需重复放行!')
|
||||
|
||||
msg = mw.getInfo('放行端口[{1}][{2}]成功', (port, protocol,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,protocol,ps,addtime',
|
||||
(port, protocol, ps, addtime))
|
||||
|
||||
self.addAcceptPort(port, protocol)
|
||||
self.firewallReload()
|
||||
return mw.returnData(True, '添加放行(' + port + ')端口成功!')
|
||||
|
||||
# 删除IP屏蔽
|
||||
def delDropAddressApi(self):
|
||||
if not self.getFwStatus():
|
||||
return mw.returnJson(False, '防火墙启动时,才能删除规则!')
|
||||
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
address = port
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw delete deny from ' + address + ' to any')
|
||||
elif self.__isFirewalld:
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
|
||||
elif self.__isIptables:
|
||||
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
pass
|
||||
|
||||
msg = mw.getInfo('解除IP[{1}]的屏蔽!', (address,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
mw.M('firewall').where("id=?", (sid,)).delete()
|
||||
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
def delAcceptPortArgs(self, port, protocol='tcp'):
|
||||
if self.__isUfw:
|
||||
if protocol == 'tcp':
|
||||
mw.execShell('ufw delete allow ' + port + '/tcp')
|
||||
if protocol == 'udp':
|
||||
mw.execShell('ufw delete allow ' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell('ufw delete allow ' + port + '/tcp')
|
||||
mw.execShell('ufw delete allow ' + port + '/udp')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
if protocol == 'tcp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
|
||||
if protocol == 'udp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
|
||||
elif self.__isIptables:
|
||||
if protocol == 'tcp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
if protocol == 'udp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT')
|
||||
else:
|
||||
pass
|
||||
|
||||
mw.M('firewall').where("port=?", (port,)).delete()
|
||||
|
||||
msg = mw.getInfo('删除防火墙放行端口[{1}][{2}]成功!', (port, protocol,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
|
||||
self.firewallReload()
|
||||
return True
|
||||
|
||||
# 删除放行端口
|
||||
def delAcceptPortApi(self):
|
||||
port = request.form.get('port', '').strip()
|
||||
protocol = request.form.get('protocol', 'tcp').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
mw_port = mw.readFile('data/port.pl')
|
||||
|
||||
if(port == mw_port):
|
||||
return mw.returnJson(False, '失败,不能删除当前面板端口!')
|
||||
try:
|
||||
self.delAcceptPortArgs(port, protocol)
|
||||
mw.M('firewall').where("id=?", (sid,)).delete()
|
||||
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '删除失败!:' + str(e))
|
||||
|
||||
def getWwwPathApi(self):
|
||||
path = mw.getLogsDir()
|
||||
return mw.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 getSshInfoApi(self):
|
||||
data = {}
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = mw.readFile(file)
|
||||
rep = "#*Port\s+([0-9]+)\s*\n"
|
||||
port = re.search(rep, conf).groups(0)[0]
|
||||
|
||||
isPing = True
|
||||
try:
|
||||
if mw.isAppleSystem():
|
||||
isPing = True
|
||||
else:
|
||||
file = '/etc/sysctl.conf'
|
||||
sys_conf = mw.readFile(file)
|
||||
rep = "#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)"
|
||||
tmp = re.search(rep, sys_conf).groups(0)[0]
|
||||
if tmp == '1':
|
||||
isPing = False
|
||||
except:
|
||||
isPing = True
|
||||
|
||||
# sshd 检测
|
||||
status = True
|
||||
cmd = "service sshd status | grep -P '(dead|stop)'|grep -v grep"
|
||||
ssh_status = mw.execShell(cmd)
|
||||
if ssh_status[0] != '':
|
||||
status = False
|
||||
|
||||
cmd = "systemctl status sshd.service | grep 'dead'|grep -v grep"
|
||||
ssh_status = mw.execShell(cmd)
|
||||
if ssh_status[0] != '':
|
||||
status = False
|
||||
|
||||
data['pass_prohibit_status'] = False
|
||||
# 密码登陆配置检查
|
||||
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_status = re.search(pass_rep, conf)
|
||||
if pass_status:
|
||||
if pass_status and pass_status.groups(0)[0].strip() == 'no':
|
||||
data['pass_prohibit_status'] = True
|
||||
else:
|
||||
data['pass_prohibit_status'] = True
|
||||
|
||||
data['port'] = port
|
||||
data['status'] = status
|
||||
data['ping'] = isPing
|
||||
if mw.isAppleSystem():
|
||||
data['firewall_status'] = False
|
||||
else:
|
||||
data['firewall_status'] = self.getFwStatus()
|
||||
return mw.getJson(data)
|
||||
|
||||
def setSshPortApi(self):
|
||||
port = request.form.get('port', '1').strip()
|
||||
if int(port) < 22 or int(port) > 65535:
|
||||
return mw.returnJson(False, '端口范围必需在22-65535之间!')
|
||||
|
||||
ports = ['21', '25', '80', '443', '888']
|
||||
if port in ports:
|
||||
return mw.returnJson(False, '(' + port + ')' + '特殊端口不可设置!')
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = mw.readFile(file)
|
||||
|
||||
rep = "#*Port\s+([0-9]+)\s*\n"
|
||||
conf = re.sub(rep, "Port " + port + "\n", conf)
|
||||
mw.writeFile(file, conf)
|
||||
|
||||
self.addAcceptPortArgs(port, 'SSH端口修改', 'port')
|
||||
if self.__isUfw:
|
||||
mw.execShell("service ssh restart")
|
||||
elif self.__isIptables:
|
||||
mw.execShell("/etc/init.d/sshd restart")
|
||||
elif self.__isFirewalld:
|
||||
mw.execShell("systemctl restart sshd.service")
|
||||
else:
|
||||
return mw.returnJson(False, '修改失败!')
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
def setSshStatusApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能操作!')
|
||||
|
||||
status = request.form.get('status', '1').strip()
|
||||
msg = 'SSH服务已启用'
|
||||
act = 'start'
|
||||
if status == "1":
|
||||
msg = 'SSH服务已停用'
|
||||
act = 'stop'
|
||||
|
||||
ssh_service = mw.systemdCfgDir() + '/sshd.service'
|
||||
if os.path.exists(ssh_service):
|
||||
mw.execShell("systemctl " + act + " sshd.service")
|
||||
else:
|
||||
mw.execShell('service sshd ' + act)
|
||||
|
||||
if os.path.exists('/etc/init.d/sshd'):
|
||||
mw.execShell('/etc/init.d/sshd ' + act)
|
||||
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
return mw.returnJson(True, '操作成功!')
|
||||
|
||||
def setSshPassStatusApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能操作!')
|
||||
|
||||
status = request.form.get('status', '1').strip()
|
||||
msg = '禁止密码登陆成功'
|
||||
if status == "1":
|
||||
msg = '开启密码登陆成功'
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
if not os.path.exists(file):
|
||||
return mw.returnJson(False, '无法设置!')
|
||||
|
||||
conf = mw.readFile(file)
|
||||
|
||||
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_status = re.search(pass_rep, conf)
|
||||
if not pass_status:
|
||||
rep = "(#)?PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication yes\n", conf)
|
||||
|
||||
if status == '1':
|
||||
rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication yes\n", conf)
|
||||
else:
|
||||
rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication no\n", conf)
|
||||
mw.writeFile(file, conf)
|
||||
mw.execShell("systemctl restart sshd.service")
|
||||
mw.writeLog("SSH管理", msg)
|
||||
return mw.returnJson(True, msg)
|
||||
|
||||
def setPingApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能操作!')
|
||||
|
||||
status = request.form.get('status')
|
||||
filename = '/etc/sysctl.conf'
|
||||
conf = mw.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
|
||||
|
||||
mw.writeFile(filename, conf)
|
||||
mw.execShell('sysctl -p')
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def setFwApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能设置!')
|
||||
|
||||
status = request.form.get('status', '1')
|
||||
return mw.getJson(self.setFw(status))
|
||||
|
||||
def setFwIptables(self, status):
|
||||
# iptables特殊处理
|
||||
if status == '1':
|
||||
mw.execShell('service iptables save')
|
||||
mw.execShell('service iptables stop')
|
||||
else:
|
||||
# 重新导入数据
|
||||
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
|
||||
'0,1000').order('id desc').select()
|
||||
|
||||
mw.execShell('iptables -P INPUT DROP')
|
||||
mw.execShell('iptables -P OUTPUT ACCEPT')
|
||||
for x in _list:
|
||||
port = x['port']
|
||||
if mw.isIpAddr(port):
|
||||
cmd = 'iptables -I INPUT -s ' + port + ' -j DROP'
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
self.addAcceptPort(port)
|
||||
|
||||
mw.execShell('service iptables save')
|
||||
mw.execShell('service iptables start')
|
||||
|
||||
def setFw(self, status):
|
||||
|
||||
if self.__isIptables:
|
||||
self.setFwIptables(status)
|
||||
return mw.returnData(True, '设置成功!')
|
||||
|
||||
if status == '1':
|
||||
if self.__isUfw:
|
||||
mw.execShell('/usr/sbin/ufw disable')
|
||||
|
||||
elif self.__isFirewalld:
|
||||
mw.execShell('systemctl stop firewalld.service')
|
||||
mw.execShell('systemctl disable firewalld.service')
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
if self.__isUfw:
|
||||
mw.execShell("echo 'y'| ufw enable")
|
||||
elif self.__isFirewalld:
|
||||
mw.execShell('systemctl start firewalld.service')
|
||||
mw.execShell('systemctl enable firewalld.service')
|
||||
else:
|
||||
pass
|
||||
|
||||
return mw.returnData(True, '设置成功!')
|
||||
|
||||
##### ----- start ----- ###
|
||||
|
||||
def getList(self, page, limit):
|
||||
|
||||
start = (page - 1) * limit
|
||||
|
||||
_list = mw.M('firewall').field('id,port,protocol,ps,addtime').limit(
|
||||
str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
|
||||
count = mw.M('firewall').count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'showAccept'
|
||||
_page['p'] = page
|
||||
|
||||
data['page'] = mw.getPage(_page)
|
||||
return mw.getJson(data)
|
||||
|
||||
def addAcceptPort(self, port, protocol='tcp'):
|
||||
if self.__isUfw:
|
||||
if protocol == 'tcp':
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
if protocol == 'udp':
|
||||
mw.execShell('ufw allow ' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
mw.execShell('ufw allow ' + port + '/udp')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
if protocol == 'tcp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'udp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/udp'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp/udp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/udp'
|
||||
mw.execShell(cmd)
|
||||
elif self.__isIptables:
|
||||
if protocol == 'tcp':
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'udp':
|
||||
cmd = 'iptables -I INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp/udp':
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
cmd = 'iptables -I INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
pass
|
||||
return True
|
||||
|
||||
def firewallReload(self):
|
||||
if self.__isUfw:
|
||||
mw.execShell('/usr/sbin/ufw reload')
|
||||
return
|
||||
elif self.__isIptables:
|
||||
mw.execShell('service iptables save')
|
||||
mw.execShell('service iptables restart')
|
||||
elif self.__isFirewalld:
|
||||
mw.execShell('firewall-cmd --reload')
|
||||
else:
|
||||
pass
|
||||
|
||||
def getFwStatus(self):
|
||||
if self.__isUfw:
|
||||
cmd = "/usr/sbin/ufw status| grep Status | awk -F ':' '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0].strip() == 'inactive':
|
||||
return False
|
||||
return True
|
||||
elif self.__isIptables:
|
||||
cmd = "systemctl status iptables | grep 'inactive'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0] != '':
|
||||
return False
|
||||
return True
|
||||
elif self.__isFirewalld:
|
||||
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0] == '':
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -1,354 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 日志类操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from datetime import datetime
|
||||
from flask import request
|
||||
|
||||
|
||||
class logs_api:
|
||||
|
||||
__months = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
|
||||
'Jul': '07', 'Aug': '08', 'Sep': '09', 'Sept': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def delPanelLogsApi(self):
|
||||
mw.M('logs').where('id>?', (0,)).delete()
|
||||
mw.writeLog('面板设置', '面板操作日志已清空!')
|
||||
return mw.returnJson(True, '面板操作日志已清空!')
|
||||
|
||||
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 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 = mw.M('logs').where(find_search, ()).field(
|
||||
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
|
||||
count = mw.M('logs').where(find_search, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'getLogs'
|
||||
_page['p'] = page
|
||||
|
||||
data['page'] = mw.getPage(_page)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getLogsTitle(self, log_name):
|
||||
log_name = log_name.replace('.1', '')
|
||||
if log_name in ['mw-update.log']:
|
||||
return '面板更新日志'
|
||||
if log_name in ['mw-install.log']:
|
||||
return '面板安装日志'
|
||||
if log_name in ['auth.log', 'secure'] or log_name.find('auth.') == 0:
|
||||
return '授权日志'
|
||||
if log_name in ['dmesg'] or log_name.find('dmesg') == 0:
|
||||
return '内核缓冲区日志'
|
||||
if log_name in ['syslog'] or log_name.find('syslog') == 0:
|
||||
return '系统日志'
|
||||
if log_name in ['rsyncd.log']:
|
||||
return '远程同步日志'
|
||||
if log_name in ['btmp']:
|
||||
return '失败的登录记录'
|
||||
if log_name in ['utmp', 'wtmp']:
|
||||
return '登录和重启记录'
|
||||
if log_name in ['lastlog']:
|
||||
return '用户最后登录'
|
||||
if log_name in ['yum.log']:
|
||||
return 'yum包管理器日志'
|
||||
if log_name in ['anaconda.log']:
|
||||
return 'Anaconda日志'
|
||||
if log_name in ['dpkg.log']:
|
||||
return 'dpkg日志'
|
||||
if log_name in ['daemon.log']:
|
||||
return '系统后台守护进程日志'
|
||||
if log_name in ['boot.log']:
|
||||
return '启动日志'
|
||||
if log_name in ['kern.log']:
|
||||
return '内核日志'
|
||||
if log_name in ['maillog', 'mail.log']:
|
||||
return '邮件日志'
|
||||
if log_name.find('Xorg') == 0:
|
||||
return 'Xorg日志'
|
||||
if log_name in ['cron.log']:
|
||||
return '定时任务日志'
|
||||
if log_name in ['alternatives.log']:
|
||||
return '更新替代信息'
|
||||
if log_name in ['debug']:
|
||||
return '调试信息'
|
||||
if log_name.find('apt') == 0:
|
||||
return 'apt-get相关日志'
|
||||
if log_name.find('installer') == 0:
|
||||
return '系统安装相关日志'
|
||||
if log_name in ['messages']:
|
||||
return '综合日志'
|
||||
return '{}日志'.format(log_name.split('.')[0])
|
||||
|
||||
def getAuditLogsFilesApi(self):
|
||||
log_dir = '/var/log'
|
||||
log_files = []
|
||||
for log_file in os.listdir(log_dir):
|
||||
log_suffix = log_file.split('.')[-1:]
|
||||
if log_suffix[0] in ['gz', 'xz', 'bz2', 'asl']:
|
||||
continue
|
||||
|
||||
if log_file in ['.', '..', 'faillog', 'fontconfig.log', 'unattended-upgrades', 'tallylog']:
|
||||
continue
|
||||
|
||||
filename = os.path.join(log_dir, log_file)
|
||||
if os.path.isfile(filename):
|
||||
file_size = os.path.getsize(filename)
|
||||
if not file_size:
|
||||
continue
|
||||
|
||||
tmp = {
|
||||
'name': log_file,
|
||||
'size': file_size,
|
||||
'log_file': filename,
|
||||
'title': self.getLogsTitle(log_file),
|
||||
'uptime': os.path.getmtime(filename)
|
||||
}
|
||||
|
||||
log_files.append(tmp)
|
||||
else:
|
||||
for next_name in os.listdir(filename):
|
||||
if next_name[-3:] in ['.gz', '.xz']:
|
||||
continue
|
||||
next_file = os.path.join(filename, next_name)
|
||||
if not os.path.isfile(next_file):
|
||||
continue
|
||||
file_size = os.path.getsize(next_file)
|
||||
if not file_size:
|
||||
continue
|
||||
log_name = '{}/{}'.format(log_file, next_name)
|
||||
tmp = {
|
||||
'name': log_name,
|
||||
'size': file_size,
|
||||
'log_file': next_file,
|
||||
'title': self.getLogsTitle(log_name),
|
||||
'uptime': os.path.getmtime(next_file)
|
||||
}
|
||||
log_files.append(tmp)
|
||||
log_files = sorted(log_files, key=lambda x: x['name'], reverse=True)
|
||||
return mw.getJson(log_files)
|
||||
|
||||
def getAuditFileApi(self):
|
||||
log_name = request.form.get('log_name', '').strip()
|
||||
return self.getAuditLogsName(log_name)
|
||||
|
||||
def __to_date2(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1],
|
||||
tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date3(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(datetime.now().year) + '-' + \
|
||||
self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date4(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(datetime.now().year) + '-' + \
|
||||
self.__months.get(tmp[0], tmp[0]) + '-' + tmp[1] + ' ' + tmp[2]
|
||||
return s_date
|
||||
|
||||
def getAuditLast(self, log_name):
|
||||
# 获取日志
|
||||
cmd = '''LANG=en_US.UTF-8 last -n 200 -x -f {} |grep -v 127.0.0.1|grep -v " begins"'''.format(
|
||||
'/var/log/' + log_name)
|
||||
result = mw.execShell(cmd)
|
||||
lastlog_list = []
|
||||
for _line in result[0].split("\n"):
|
||||
if not _line:
|
||||
continue
|
||||
tmp = {}
|
||||
sp_arr = _line.split()
|
||||
tmp['用户'] = sp_arr[0]
|
||||
if sp_arr[0] == 'runlevel':
|
||||
tmp['来源'] = sp_arr[4]
|
||||
tmp['端口'] = ' '.join(sp_arr[1:4])
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[5:])) + ' ' + ' '.join(sp_arr[-2:])
|
||||
elif sp_arr[0] in ['reboot', 'shutdown']:
|
||||
tmp['来源'] = sp_arr[3]
|
||||
tmp['端口'] = ' '.join(sp_arr[1:3])
|
||||
if sp_arr[-3] == '-':
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
else:
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-2:])
|
||||
elif sp_arr[1] in ['tty1', 'tty', 'tty2', 'tty3', 'hvc0', 'hvc1', 'hvc2'] or len(sp_arr) == 9:
|
||||
tmp['来源'] = ''
|
||||
tmp['端口'] = sp_arr[1]
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[2:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
else:
|
||||
tmp['来源'] = sp_arr[2]
|
||||
tmp['端口'] = sp_arr[1]
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[3:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
|
||||
# tmp['_line'] = _line
|
||||
lastlog_list.append(tmp)
|
||||
# lastlog_list = sorted(lastlog_list,key=lambda x:x['时间'],reverse=True)
|
||||
return mw.returnData(True, 'ok!', lastlog_list)
|
||||
|
||||
def getAuditLastLog(self):
|
||||
cmd = '''LANG=en_US.UTF-8 lastlog|grep -v Username'''
|
||||
result = mw.execShell(cmd)
|
||||
lastlog_list = []
|
||||
for _line in result[0].split("\n"):
|
||||
if not _line:
|
||||
continue
|
||||
tmp = {}
|
||||
sp_arr = _line.split()
|
||||
tmp['用户'] = sp_arr[0]
|
||||
# tmp['_line'] = _line
|
||||
if _line.find('Never logged in') != -1:
|
||||
tmp['最后登录时间'] = '0'
|
||||
tmp['最后登录来源'] = '-'
|
||||
tmp['最后登录端口'] = '-'
|
||||
lastlog_list.append(tmp)
|
||||
continue
|
||||
tmp['最后登录来源'] = sp_arr[2]
|
||||
tmp['最后登录端口'] = sp_arr[1]
|
||||
tmp['最后登录时间'] = self.__to_date2(' '.join(sp_arr[3:]))
|
||||
|
||||
lastlog_list.append(tmp)
|
||||
lastlog_list = sorted(lastlog_list, key=lambda x: x[
|
||||
'最后登录时间'], reverse=True)
|
||||
for i in range(len(lastlog_list)):
|
||||
if lastlog_list[i]['最后登录时间'] == '0':
|
||||
lastlog_list[i]['最后登录时间'] = '从未登录过'
|
||||
return mw.returnData(True, 'ok!', lastlog_list)
|
||||
|
||||
def parseAuditFile(self, log_name, result):
|
||||
log_list = []
|
||||
is_string = True
|
||||
for _line in result.split("\n"):
|
||||
if not _line.strip():
|
||||
continue
|
||||
if log_name.find('sa/sa') == -1:
|
||||
if _line[:3] in self.__months:
|
||||
_msg = _line[16:]
|
||||
_tmp = _msg.split(": ")
|
||||
_act = ''
|
||||
if len(_tmp) > 1:
|
||||
_act = _tmp[0]
|
||||
_msg = _tmp[1]
|
||||
else:
|
||||
_msg = _tmp[0]
|
||||
_line = {
|
||||
"时间": self.__to_date4(_line[:16].strip()),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
elif _line[:2] in ['19', '20', '21', '22', '23', '24']:
|
||||
_msg = _line[19:]
|
||||
_tmp = _msg.split(" ")
|
||||
_act = _tmp[1]
|
||||
_msg = ' '.join(_tmp[2:])
|
||||
_line = {
|
||||
"时间": _line[:19].strip(),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
elif log_name.find('alternatives') == 0:
|
||||
_tmp = _line.split(": ")
|
||||
_last = _tmp[0].split(" ")
|
||||
_act = _last[0]
|
||||
_msg = ' '.join(_tmp[1:])
|
||||
_line = {
|
||||
"时间": ' '.join(_last[1:]).strip(),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
else:
|
||||
if not is_string:
|
||||
if type(_line) != dict:
|
||||
continue
|
||||
|
||||
log_list.append(_line)
|
||||
|
||||
return log_list
|
||||
|
||||
def getAuditLogsName(self, log_name):
|
||||
# print(log_name)
|
||||
if log_name in ['wtmp', 'btmp', 'utmp'] or log_name.find('wtmp') == 0 or log_name.find('btmp') == 0 or log_name.find('utmp') == 0:
|
||||
return self.getAuditLast(log_name)
|
||||
|
||||
if log_name.find('lastlog') == 0:
|
||||
return self.getAuditLastLog()
|
||||
|
||||
if log_name.find('sa/sa') == 0:
|
||||
if log_name.find('sa/sar') == -1:
|
||||
return mw.execShell("sar -f /var/log/{}".format(log_name))[0]
|
||||
log_dir = '/var/log'
|
||||
log_file = log_dir + '/' + log_name
|
||||
if not os.path.exists(log_file):
|
||||
return mw.returnData(False, '日志文件不存在!')
|
||||
result = mw.getLastLine(log_file, 100)
|
||||
try:
|
||||
log_list = self.parseAuditFile(log_name, result)
|
||||
_string = []
|
||||
_dict = []
|
||||
_list = []
|
||||
for _line in log_list:
|
||||
if isinstance(_line, str):
|
||||
_string.append(_line.strip())
|
||||
elif isinstance(_line, dict):
|
||||
_dict.append(_line)
|
||||
elif isinstance(_line, list):
|
||||
_list.append(_line)
|
||||
else:
|
||||
continue
|
||||
_str_len = len(_string)
|
||||
_dict_len = len(_dict)
|
||||
_list_len = len(_list)
|
||||
if _str_len > _dict_len + _list_len:
|
||||
return "\n".join(_string)
|
||||
elif _dict_len > _str_len + _list_len:
|
||||
return mw.returnData(True, 'ok!', _dict)
|
||||
else:
|
||||
return mw.returnData(True, 'ok!', _list)
|
||||
|
||||
except:
|
||||
return mw.returnData(True, 'ok!', result)
|
||||
-2212
File diff suppressed because it is too large
Load Diff
+26
-49
@@ -1,20 +1,8 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 分页库操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import math
|
||||
import string
|
||||
import public
|
||||
|
||||
|
||||
class Page():
|
||||
@@ -39,10 +27,10 @@ class Page():
|
||||
__RTURN_JS = False # 是否返回JS回调
|
||||
__START_NUM = None # 起始行
|
||||
__END_NUM = None # 结束行
|
||||
__ARGS_TPL = ''
|
||||
|
||||
def __init__(self):
|
||||
if False:
|
||||
tmp = public.getMsg('PAGE')
|
||||
if tmp:
|
||||
self.__PREV = tmp['PREV']
|
||||
self.__NEXT = tmp['NEXT']
|
||||
self.__START = tmp['START']
|
||||
@@ -52,19 +40,12 @@ class Page():
|
||||
self.__FO = tmp['FO']
|
||||
self.__LINE = tmp['LINE']
|
||||
|
||||
def getPageNum(self, num):
|
||||
return str(num) + self.__ARGS_TPL
|
||||
|
||||
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
|
||||
# 取分页信息
|
||||
# @param pageInfo 传入分页参数字典
|
||||
# @param limit 返回系列
|
||||
self.__RTURN_JS = pageInfo['return_js']
|
||||
self.__COUNT_ROW = pageInfo['count']
|
||||
|
||||
if 'args_tpl' in pageInfo:
|
||||
self.__ARGS_TPL = pageInfo['args_tpl']
|
||||
|
||||
self.ROW = pageInfo['row']
|
||||
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
|
||||
self.__START_NUM = self.__StartRow()
|
||||
@@ -74,6 +55,7 @@ class Page():
|
||||
self.SHIFT = self.__START_NUM - 1
|
||||
|
||||
keys = limit.split(',')
|
||||
|
||||
pages = {}
|
||||
# 起始页
|
||||
pages['1'] = self.__GetStart()
|
||||
@@ -88,16 +70,14 @@ class Page():
|
||||
|
||||
# 当前显示页与总页数
|
||||
pages['6'] = "<span class='Pnumber'>" + \
|
||||
str(self.__C_PAGE) + "/" + \
|
||||
str(self.__COUNT_PAGE) + "</span>"
|
||||
|
||||
bytes(self.__C_PAGE) + "/" + bytes(self.__COUNT_PAGE) + "</span>"
|
||||
# 本页显示开始与结束行
|
||||
pages['7'] = "<span class='Pline'>" + str(self.__FO) + \
|
||||
str(self.__START_NUM) + "-" + \
|
||||
str(self.__END_NUM) + str(self.__LINE) + "</span>"
|
||||
pages['7'] = "<span class='Pline'>" + self.__FO + \
|
||||
bytes(self.__START_NUM) + "-" + \
|
||||
bytes(self.__END_NUM) + self.__LINE + "</span>"
|
||||
# 行数
|
||||
pages['8'] = "<span class='Pcount'>" + str(self.__COUNT_START) + \
|
||||
str(self.__COUNT_ROW) + str(self.__COUNT_END) + "</span>"
|
||||
pages['8'] = "<span class='Pcount'>" + self.__COUNT_START + \
|
||||
bytes(self.__COUNT_ROW) + self.__COUNT_END + "</span>"
|
||||
|
||||
# 构造返回数据
|
||||
retuls = '<div>'
|
||||
@@ -116,11 +96,10 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
endStr = "<a class='Pend' href='" + self.__URI + "p=" + \
|
||||
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
|
||||
bytes(self.__COUNT_PAGE) + "'>" + self.__END + "</a>"
|
||||
else:
|
||||
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
|
||||
"(" + self.getPageNum(self.__COUNT_PAGE) + ")'>" + \
|
||||
str(self.__END) + "</a>"
|
||||
"(" + bytes(self.__COUNT_PAGE) + ")'>" + self.__END + "</a>"
|
||||
return endStr
|
||||
|
||||
def __GetNext(self):
|
||||
@@ -131,11 +110,10 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + \
|
||||
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
|
||||
bytes(self.__C_PAGE + 1) + "'>" + self.__NEXT + "</a>"
|
||||
else:
|
||||
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
|
||||
"(" + self.getPageNum(self.__C_PAGE + 1) + ")'>" + \
|
||||
str(self.__NEXT) + "</a>"
|
||||
"(" + bytes(self.__C_PAGE + 1) + ")'>" + self.__NEXT + "</a>"
|
||||
|
||||
return nextStr
|
||||
|
||||
@@ -156,15 +134,15 @@ class Page():
|
||||
if page > 0:
|
||||
if self.__RTURN_JS == "":
|
||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
||||
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
|
||||
|
||||
# 当前页
|
||||
if self.__C_PAGE > 0:
|
||||
pages += "<span class='Pcurrent'>" + \
|
||||
str(self.__C_PAGE) + "</span>"
|
||||
bytes(self.__C_PAGE) + "</span>"
|
||||
|
||||
# 当前页之后
|
||||
if self.__C_PAGE <= self.__LIST_NUM:
|
||||
@@ -179,10 +157,10 @@ class Page():
|
||||
break
|
||||
if self.__RTURN_JS == "":
|
||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
||||
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
|
||||
|
||||
return pages
|
||||
|
||||
@@ -194,11 +172,10 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + \
|
||||
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
|
||||
bytes(self.__C_PAGE - 1) + "'>" + self.__PREV + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
|
||||
"(" + self.getPageNum(self.__C_PAGE - 1) + ")'>" + \
|
||||
str(self.__PREV) + "</a>"
|
||||
"(" + bytes(self.__C_PAGE - 1) + ")'>" + self.__PREV + "</a>"
|
||||
return startStr
|
||||
|
||||
def __GetStart(self):
|
||||
@@ -209,10 +186,10 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
startStr = "<a class='Pstart' href='" + \
|
||||
self.__URI + "p=1'>" + str(self.__START) + "</a>"
|
||||
self.__URI + "p=1'>" + self.__START + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Pstart' onclick='" + \
|
||||
self.__RTURN_JS + "("+self.getPageNum(1)+")'>" + str(self.__START) + "</a>"
|
||||
self.__RTURN_JS + "(1)'>" + self.__START + "</a>"
|
||||
return startStr
|
||||
|
||||
def __GetCpage(self, p):
|
||||
@@ -235,11 +212,11 @@ class Page():
|
||||
# 取总页数
|
||||
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
|
||||
|
||||
def __SetUri(self, sinput):
|
||||
def __SetUri(self, input):
|
||||
# 构造URI
|
||||
uri = '?'
|
||||
for key in sinput:
|
||||
for key in input:
|
||||
if key == 'p':
|
||||
continue
|
||||
uri += key + '=' + sinput[key] + '&'
|
||||
uri += key + '=' + input[key] + '&'
|
||||
return str(uri)
|
||||
|
||||
Executable
+291
@@ -0,0 +1,291 @@
|
||||
# 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
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+733
@@ -0,0 +1,733 @@
|
||||
# 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
|
||||
|
||||
import db
|
||||
|
||||
from random import Random
|
||||
|
||||
|
||||
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
|
||||
if shell:
|
||||
cmdstring_list = cmdstring
|
||||
else:
|
||||
cmdstring_list = shlex.split(cmdstring)
|
||||
if timeout:
|
||||
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
||||
|
||||
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,
|
||||
shell=shell, bufsize=4096, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
if timeout:
|
||||
if end_time <= datetime.datetime.now():
|
||||
raise Exception("Timeout:%s" % cmdstring)
|
||||
|
||||
return sub.communicate()
|
||||
|
||||
|
||||
def getRunDir():
|
||||
return os.getcwd()
|
||||
|
||||
|
||||
def getRootDir():
|
||||
return os.path.dirname(os.path.dirname(getRunDir()))
|
||||
|
||||
|
||||
def getOs():
|
||||
os = execShell('uname')
|
||||
return os[0].lower().strip()
|
||||
|
||||
|
||||
def M(table):
|
||||
sql = db.Sql()
|
||||
return sql.table(table)
|
||||
|
||||
|
||||
def getPage(args, result='1,2,3,4,5,8'):
|
||||
# 取分页
|
||||
import page
|
||||
# 实例化分页类
|
||||
page = page.Page()
|
||||
info = {}
|
||||
|
||||
info['count'] = 0
|
||||
if args.has_key('count'):
|
||||
info['count'] = int(args['count'])
|
||||
|
||||
info['row'] = 10
|
||||
if args.has_key('row'):
|
||||
info['row'] = args['row']
|
||||
|
||||
info['p'] = 1
|
||||
if args.has_key('p'):
|
||||
info['p'] = int(args['p'])
|
||||
info['uri'] = {}
|
||||
info['return_js'] = ''
|
||||
if args.has_key('tojs'):
|
||||
info['return_js'] = args['tojs']
|
||||
|
||||
return page.GetPage(info, result)
|
||||
|
||||
|
||||
def md5(str):
|
||||
# 生成MD5
|
||||
try:
|
||||
m = hashlib.md5()
|
||||
m.update(str)
|
||||
return m.hexdigest()
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def getFileMd5(filename):
|
||||
# 文件的MD5值
|
||||
if not os.path.isfile(filename):
|
||||
return False
|
||||
|
||||
myhash = hashlib.md5()
|
||||
f = file(filename, 'rb')
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b:
|
||||
break
|
||||
myhash.update(b)
|
||||
f.close()
|
||||
return myhash.hexdigest()
|
||||
|
||||
|
||||
def getRandomString(length):
|
||||
# 取随机字符串
|
||||
str = ''
|
||||
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||
chrlen = len(chars) - 1
|
||||
random = Random()
|
||||
for i in range(length):
|
||||
str += chars[random.randint(0, chrlen)]
|
||||
return str
|
||||
|
||||
|
||||
def getJson(data):
|
||||
import json
|
||||
return json.dumps(data)
|
||||
|
||||
|
||||
def returnJson(status, msg, args=()):
|
||||
# 取通用Json返回
|
||||
return getJson(returnMsg(status, msg, args))
|
||||
|
||||
|
||||
def returnMsg(status, msg, args=()):
|
||||
# 取通用字曲返回
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + getLanguage() + '/public.json'))
|
||||
keys = logMessage.keys()
|
||||
|
||||
if msg in keys:
|
||||
msg = logMessage[msg]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
msg = msg.replace(rep, args[i])
|
||||
return {'status': status, 'msg': msg, 'data': args}
|
||||
|
||||
|
||||
def getInfo(msg, args=()):
|
||||
# 取提示消息
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
msg = msg.replace(rep, args[i])
|
||||
return msg
|
||||
|
||||
|
||||
def getMsg(key, args=()):
|
||||
# 取提示消息
|
||||
try:
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + getLanguage() + '/public.json'))
|
||||
keys = logMessage.keys()
|
||||
msg = None
|
||||
if key in keys:
|
||||
msg = logMessage[key]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
msg = msg.replace(rep, args[i])
|
||||
return msg
|
||||
except:
|
||||
return key
|
||||
|
||||
|
||||
def getLan(key):
|
||||
# 取提示消息
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + getLanguage() + '/template.json'))
|
||||
keys = logMessage.keys()
|
||||
msg = None
|
||||
if key in keys:
|
||||
msg = logMessage[key]
|
||||
return msg
|
||||
|
||||
|
||||
def readFile(filename):
|
||||
# 读文件内容
|
||||
try:
|
||||
fp = open(filename, 'r')
|
||||
fBody = fp.read()
|
||||
fp.close()
|
||||
return fBody
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def getDate():
|
||||
# 取格式时间
|
||||
import time
|
||||
return time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
|
||||
|
||||
def getLanguage():
|
||||
path = 'data/language.pl'
|
||||
if not os.path.exists(path):
|
||||
return 'Simplified_Chinese'
|
||||
return readFile(path).strip()
|
||||
|
||||
|
||||
def writeLog(type, logMsg, args=()):
|
||||
# 写日志
|
||||
try:
|
||||
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
|
||||
|
||||
|
||||
def writeFile(filename, str):
|
||||
# 写文件内容
|
||||
try:
|
||||
fp = open(filename, 'w+')
|
||||
fp.write(str)
|
||||
fp.close()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def httpGet(url, timeout=30):
|
||||
# 发送GET请求
|
||||
try:
|
||||
import urllib2
|
||||
import ssl
|
||||
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)
|
||||
|
||||
|
||||
def httpPost(url, data, timeout=30):
|
||||
# 发送POST请求
|
||||
try:
|
||||
import urllib
|
||||
import urllib2
|
||||
import ssl
|
||||
try:
|
||||
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)
|
||||
|
||||
|
||||
def writeSpeed(title, used, total, speed=0):
|
||||
# 写进度
|
||||
if not title:
|
||||
data = {'title': None, 'progress': 0,
|
||||
'total': 0, 'used': 0, 'speed': 0}
|
||||
else:
|
||||
progress = int((100.0 * used / total))
|
||||
data = {'title': title, 'progress': progress,
|
||||
'total': total, 'used': used, 'speed': speed}
|
||||
writeFile('/tmp/panelSpeed.pl', json.dumps(data))
|
||||
return True
|
||||
|
||||
|
||||
def getSpeed():
|
||||
# 取进度
|
||||
data = readFile('/tmp/panelSpeed.pl')
|
||||
if not data:
|
||||
data = json.dumps({'title': None, 'progress': 0,
|
||||
'total': 0, 'used': 0, 'speed': 0})
|
||||
writeFile('/tmp/panelSpeed.pl', data)
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def getLastLine(inputfile, lineNum):
|
||||
# 读文件指定倒数行数
|
||||
try:
|
||||
fp = open(inputfile, 'r')
|
||||
lastLine = ""
|
||||
|
||||
lines = fp.readlines()
|
||||
count = len(lines)
|
||||
if count > lineNum:
|
||||
num = lineNum
|
||||
else:
|
||||
num = count
|
||||
i = 1
|
||||
lastre = []
|
||||
for i in range(1, (num + 1)):
|
||||
if lines:
|
||||
n = -i
|
||||
lastLine = lines[n].strip()
|
||||
fp.close()
|
||||
lastre.append(lastLine)
|
||||
|
||||
result = ''
|
||||
num -= 1
|
||||
while num >= 0:
|
||||
result += lastre[num] + "\n"
|
||||
num -= 1
|
||||
return result
|
||||
except:
|
||||
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 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')
|
||||
|
||||
|
||||
def downloadFile(url, filename):
|
||||
import urllib
|
||||
urllib.urlretrieve(url, filename=filename, reporthook=downloadHook)
|
||||
|
||||
|
||||
def downloadHook(count, blockSize, totalSize):
|
||||
speed = {'total': totalSize, 'block': blockSize, 'count': count}
|
||||
print speed
|
||||
print '%02d%%' % (100.0 * count * blockSize / totalSize)
|
||||
|
||||
|
||||
def GetLocalIp():
|
||||
# 取本地外网IP
|
||||
try:
|
||||
import re
|
||||
filename = 'data/iplist.txt'
|
||||
ipaddress = readFile(filename)
|
||||
if not ipaddress:
|
||||
import urllib2
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
opener = urllib2.urlopen(url)
|
||||
str = opener.read()
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', str).group(0)
|
||||
writeFile(filename, ipaddress)
|
||||
|
||||
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]
|
||||
|
||||
|
||||
def inArray(arrays, searchStr):
|
||||
# 搜索数据中是否存在
|
||||
for key in arrays:
|
||||
if key == searchStr:
|
||||
return True
|
||||
|
||||
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
|
||||
p = re.compile(
|
||||
'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
|
||||
if p.match(ip):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def checkPort(port):
|
||||
# 检查端口是否合法
|
||||
ports = ['21', '25', '443', '8080', '888', '8888', '8443']
|
||||
if port in ports:
|
||||
return False
|
||||
intport = int(port)
|
||||
if intport < 1 or intport > 65535:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def getStrBetween(startStr, endStr, srcStr):
|
||||
# 字符串取中间
|
||||
start = srcStr.find(startStr)
|
||||
if start == -1:
|
||||
return None
|
||||
end = srcStr.find(endStr)
|
||||
if end == -1:
|
||||
return None
|
||||
return srcStr[start + 1:end]
|
||||
|
||||
|
||||
def getCpuType():
|
||||
# 取CPU类型
|
||||
cpuinfo = open('/proc/cpuinfo', 'r').read()
|
||||
rep = "model\s+name\s+:\s+(.+)"
|
||||
tmp = re.search(rep, cpuinfo)
|
||||
cpuType = None
|
||||
if tmp:
|
||||
cpuType = tmp.groups()[0]
|
||||
return cpuType
|
||||
|
||||
|
||||
def isRestart():
|
||||
# 检查是否允许重启
|
||||
num = M('tasks').where('status!=?', ('1',)).count()
|
||||
if num > 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
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):
|
||||
start = time.time()
|
||||
result = httpGet(url)
|
||||
if result != 'True':
|
||||
return False
|
||||
return int((time.time() - start) * 1000)
|
||||
|
||||
|
||||
def auth_decode(data):
|
||||
# 解密数据
|
||||
token = GetToken()
|
||||
# 是否有生成Token
|
||||
if not token:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 校验access_key是否正确
|
||||
if token['access_key'] != data['btauth_key']:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 解码数据
|
||||
import binascii
|
||||
import hashlib
|
||||
import urllib
|
||||
import hmac
|
||||
import json
|
||||
tdata = binascii.unhexlify(data['data'])
|
||||
|
||||
# 校验signature是否正确
|
||||
signature = binascii.hexlify(
|
||||
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
|
||||
if signature != data['signature']:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 返回
|
||||
return json.loads(urllib.unquote(tdata))
|
||||
|
||||
|
||||
# 数据加密
|
||||
def auth_encode(data):
|
||||
token = GetToken()
|
||||
pdata = {}
|
||||
|
||||
# 是否有生成Token
|
||||
if not token:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 生成signature
|
||||
import binascii
|
||||
import hashlib
|
||||
import urllib
|
||||
import hmac
|
||||
import json
|
||||
tdata = urllib.quote(json.dumps(data))
|
||||
# 公式 hex(hmac_sha256(data))
|
||||
pdata['signature'] = binascii.hexlify(
|
||||
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
|
||||
|
||||
# 加密数据
|
||||
pdata['btauth_key'] = token['access_key']
|
||||
pdata['data'] = binascii.hexlify(tdata)
|
||||
pdata['timestamp'] = time.time()
|
||||
|
||||
# 返回
|
||||
return pdata
|
||||
|
||||
|
||||
def checkToken(get):
|
||||
# 检查Token
|
||||
tempFile = 'data/tempToken.json'
|
||||
if not os.path.exists(tempFile):
|
||||
return False
|
||||
import json
|
||||
import time
|
||||
tempToken = json.loads(readFile(tempFile))
|
||||
if time.time() > tempToken['timeout']:
|
||||
return False
|
||||
if get.token != tempToken['token']:
|
||||
return False
|
||||
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:
|
||||
return data
|
||||
if type(data) != str:
|
||||
return data
|
||||
checkList = [
|
||||
{'d': '<', 'r': '<'},
|
||||
{'d': '>', 'r': '>'},
|
||||
{'d': '\'', 'r': '‘'},
|
||||
{'d': '"', 'r': '“'},
|
||||
{'d': '&', 'r': '&'},
|
||||
{'d': '#', 'r': '#'},
|
||||
{'d': '<', 'r': '<'}
|
||||
]
|
||||
for v in checkList:
|
||||
data = data.replace(v['d'], v['r'])
|
||||
return data
|
||||
|
||||
|
||||
def 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'
|
||||
if not os.path.exists(openssl):
|
||||
openssl = 'openssl'
|
||||
certPem = readFile(certPath)
|
||||
s = "\n-----BEGIN CERTIFICATE-----"
|
||||
tmp = certPem.strip().split(s)
|
||||
for tmp1 in tmp:
|
||||
if tmp1.find('-----BEGIN CERTIFICATE-----') == -1:
|
||||
tmp1 = s + tmp1
|
||||
writeFile(certPath, tmp1)
|
||||
result = execShell(openssl + " x509 -in " +
|
||||
certPath + " -noout -subject")
|
||||
if result[1].find('-bash:') != -1:
|
||||
return True
|
||||
if len(result[1]) > 2:
|
||||
return False
|
||||
if result[0].find('error:') != -1:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 获取面板地址
|
||||
|
||||
|
||||
# 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):
|
||||
# 字节单位转换
|
||||
d = ('b', 'KB', 'MB', 'GB', 'TB')
|
||||
s = d[0]
|
||||
for b in d:
|
||||
if size < 1024:
|
||||
return str(size) + ' ' + b
|
||||
size = size / 1024
|
||||
s = b
|
||||
return str(size) + ' ' + b
|
||||
|
||||
|
||||
def get_string(t):
|
||||
if t != -1:
|
||||
max = 126
|
||||
m_types = [{'m': 122, 'n': 97}, {'m': 90, 'n': 65}, {'m': 57, 'n': 48}, {
|
||||
'm': 47, 'n': 32}, {'m': 64, 'n': 58}, {'m': 96, 'n': 91}, {'m': 125, 'n': 123}]
|
||||
else:
|
||||
max = 256
|
||||
t = 0
|
||||
m_types = [{'m': 255, 'n': 0}]
|
||||
arr = []
|
||||
for i in range(max):
|
||||
if i < m_types[t]['n'] or i > m_types[t]['m']:
|
||||
continue
|
||||
arr.append(chr(i))
|
||||
return arr
|
||||
|
||||
|
||||
def get_string_find(t):
|
||||
if type(t) != list:
|
||||
t = [t]
|
||||
return_str = ''
|
||||
for s1 in t:
|
||||
return_str += get_string(int(s1[0]))[int(s1[1:])]
|
||||
return return_str
|
||||
|
||||
|
||||
def get_string_arr(t):
|
||||
s_arr = {}
|
||||
t_arr = []
|
||||
for s1 in t:
|
||||
for i in range(6):
|
||||
if not i in s_arr:
|
||||
s_arr[i] = get_string(i)
|
||||
for j in range(len(s_arr[i])):
|
||||
if s1 == s_arr[i][j]:
|
||||
t_arr.append(str(i) + str(j))
|
||||
return t_arr
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,456 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# SSH终端操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import threading
|
||||
import re
|
||||
|
||||
from io import BytesIO, StringIO
|
||||
|
||||
import mw
|
||||
import paramiko
|
||||
|
||||
from flask_socketio import SocketIO, emit, send
|
||||
|
||||
|
||||
class ssh_terminal:
|
||||
|
||||
__debug_file = 'logs/terminal.log'
|
||||
__log_type = 'SSH终端'
|
||||
|
||||
# websocketio 唯一标识
|
||||
__sid = ''
|
||||
|
||||
__host = None
|
||||
__type = '0'
|
||||
__port = 22
|
||||
__user = None
|
||||
__pass = None
|
||||
__pkey = None
|
||||
__key_passwd = None
|
||||
|
||||
__rep_ssh_config = False
|
||||
__rep_ssh_service = False
|
||||
__sshd_config_backup = None
|
||||
|
||||
__ssh = None
|
||||
__tp = None
|
||||
__ps = None
|
||||
|
||||
__ssh_list = {}
|
||||
__ssh_last_request_time = {}
|
||||
|
||||
def __init__(self):
|
||||
ht = threading.Thread(target=self.heartbeat)
|
||||
ht.start()
|
||||
|
||||
def debug(self, msg):
|
||||
msg = "{} - {}:{} => {} \n".format(mw.formatDate(),
|
||||
self.__host, self.__port, msg)
|
||||
if not mw.isDebugMode():
|
||||
return
|
||||
mw.writeFile(self.__debug_file, msg, 'a+')
|
||||
|
||||
def returnMsg(self, status, msg):
|
||||
return {'status': status, 'msg': msg}
|
||||
|
||||
def restartSsh(self, act='reload'):
|
||||
'''
|
||||
重启ssh 无参数传递
|
||||
'''
|
||||
version = mw.readFile('/etc/redhat-release')
|
||||
if not os.path.exists('/etc/redhat-release'):
|
||||
mw.execShell('service ssh ' + act)
|
||||
elif version.find(' 7.') != -1 or version.find(' 8.') != -1:
|
||||
mw.execShell("systemctl " + act + " sshd.service")
|
||||
else:
|
||||
mw.execShell("/etc/init.d/sshd " + act)
|
||||
|
||||
def isRunning(self, rep=False):
|
||||
try:
|
||||
if rep and self.__rep_ssh_service:
|
||||
self.restartSsh('stop')
|
||||
return True
|
||||
|
||||
status = self.getSshStatus()
|
||||
if not status:
|
||||
self.restartSsh('start')
|
||||
self.__rep_ssh_service = True
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def setSshdConfig(self, rep=False):
|
||||
self.isRunning(rep)
|
||||
if rep and not self.__rep_ssh_config:
|
||||
return False
|
||||
|
||||
try:
|
||||
sshd_config_file = '/etc/ssh/sshd_config'
|
||||
if not os.path.exists(sshd_config_file):
|
||||
return False
|
||||
|
||||
sshd_config = mw.readFile(sshd_config_file)
|
||||
if not sshd_config:
|
||||
return False
|
||||
|
||||
if rep:
|
||||
if self.__sshd_config_backup:
|
||||
mw.writeFile(sshd_config_file, self.__sshd_config_backup)
|
||||
self.restartSsh()
|
||||
return True
|
||||
|
||||
pin = r'^\s*PubkeyAuthentication\s+(yes|no)'
|
||||
pubkey_status = re.findall(pin, sshd_config, re.I)
|
||||
if pubkey_status:
|
||||
if pubkey_status[0] == 'yes':
|
||||
pubkey_status = True
|
||||
else:
|
||||
pubkey_status = False
|
||||
|
||||
pin = r'^\s*RSAAuthentication\s+(yes|no)'
|
||||
rsa_status = re.findall(pin, sshd_config, re.I)
|
||||
if rsa_status:
|
||||
if rsa_status[0] == 'yes':
|
||||
rsa_status = True
|
||||
else:
|
||||
rsa_status = False
|
||||
|
||||
self._sshd_config_backup = sshd_config
|
||||
is_write = False
|
||||
if not pubkey_status:
|
||||
sshd_config = re.sub(
|
||||
r'\n#?PubkeyAuthentication\s\w+', '\nPubkeyAuthentication yes', sshd_config)
|
||||
is_write = True
|
||||
if not rsa_status:
|
||||
sshd_config = re.sub(
|
||||
r'\n#?RSAAuthentication\s\w+', '\nRSAAuthentication yes', sshd_config)
|
||||
is_write = True
|
||||
|
||||
if is_write:
|
||||
mw.writeFile(sshd_config_file, sshd_config)
|
||||
self.__rep_ssh_config = True
|
||||
self.restartSsh()
|
||||
else:
|
||||
self.__sshd_config_backup = None
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def setSid(self, sid):
|
||||
self.__sid = sid
|
||||
|
||||
def connect(self, sid):
|
||||
# self.connectBySocket()
|
||||
if self.__host in ['127.0.0.1', 'localhost']:
|
||||
return self.connectLocalSsh(sid)
|
||||
else:
|
||||
return self.connectBySocket(sid)
|
||||
|
||||
def connectLocalSsh(self, sid):
|
||||
mw.createSshInfo()
|
||||
self.__ps = paramiko.SSHClient()
|
||||
self.__ps.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
self.__port = mw.getSSHPort()
|
||||
try:
|
||||
self.__ps.connect(self.__host, self.__port, timeout=60)
|
||||
except Exception as e:
|
||||
self.__ps.connect('127.0.0.1', self.__port)
|
||||
except Exception as e:
|
||||
self.__ps.connect('localhost', self.__port)
|
||||
except Exception as e:
|
||||
self.setSshdConfig(True)
|
||||
self.__ps.close()
|
||||
e = str(e)
|
||||
if e.find('websocket error!') != -1:
|
||||
return self.returnMsg(True, '连接成功')
|
||||
if e.find('Authentication timeout') != -1:
|
||||
self.debug("认证超时{}".format(e))
|
||||
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
|
||||
if e.find('Connection reset by peer') != -1:
|
||||
self.debug('目标服务器主动拒绝连接')
|
||||
return self.returnMsg(False, '目标服务器主动拒绝连接')
|
||||
if e.find('Error reading SSH protocol banner') != -1:
|
||||
self.debug('协议头响应超时')
|
||||
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
|
||||
if not e:
|
||||
self.debug('SSH协议握手超时')
|
||||
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
|
||||
err = mw.getTracebackInfo()
|
||||
self.debug(err)
|
||||
return self.returnMsg(False, "未知错误: {}".format(err))
|
||||
|
||||
self.debug('local-ssh:认证成功,正在构建会话通道')
|
||||
ssh = self.__ps.invoke_shell(
|
||||
term='xterm', width=83, height=21)
|
||||
ssh.setblocking(0)
|
||||
self.__ssh_list[sid] = ssh
|
||||
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
|
||||
self.__host, self.__port))
|
||||
self.debug('local-ssh:通道已构建')
|
||||
return self.returnMsg(True, '连接成功!')
|
||||
|
||||
def connectBySocket(self, sid):
|
||||
if not self.__host:
|
||||
return self.returnMsg(False, '错误的连接地址')
|
||||
if not self.__user:
|
||||
self.__user = 'root'
|
||||
if not self.__port:
|
||||
self.__port = 22
|
||||
|
||||
self.setSshdConfig(True)
|
||||
num = 0
|
||||
while num < 5:
|
||||
num += 1
|
||||
try:
|
||||
self.debug('正在尝试第{}次连接'.format(num))
|
||||
if self.__rep_ssh_config:
|
||||
time.sleep(0.1)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(2 + num)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
|
||||
sock.connect((self.__host, self.__port))
|
||||
break
|
||||
except Exception as e:
|
||||
if num == 5:
|
||||
self.setSshdConfig(True)
|
||||
self.debug('重试连接失败,{}'.format(e))
|
||||
return self.returnMsg(False, '连接目标服务器失败, {}:{}'.format(self.__host, self.__port))
|
||||
else:
|
||||
time.sleep(0.2)
|
||||
|
||||
# print(self.__host, sock)
|
||||
self.__tp = paramiko.Transport(sock)
|
||||
try:
|
||||
self.__tp.start_client()
|
||||
self.__tp.banner_timeout = 60
|
||||
if not self.__pass and not self.__pkey:
|
||||
return self.returnMsg(False, '密码或私钥不能都为空: {}:{}'.format(self.__host, self.__port))
|
||||
|
||||
if self.__pkey != '' and self.__type != '0':
|
||||
self.debug('正在认证私钥')
|
||||
p_file = StringIO(str(self.__pkey.replace('\\n', '\n')))
|
||||
# p_file = "/tmp/t_ssh_pkey.txt"
|
||||
# mw.writeFile(p_file, self.__pkey.replace('\\n', '\n'))
|
||||
# mw.execShell('chmod 600 ' + p_file)
|
||||
try:
|
||||
p_file.seek(0)
|
||||
pkey = paramiko.RSAKey.from_private_key(p_file)
|
||||
except:
|
||||
try:
|
||||
p_file.seek(0) # 重置游标
|
||||
pkey = paramiko.Ed25519Key.from_private_key(
|
||||
p_file)
|
||||
except:
|
||||
try:
|
||||
p_file.seek(0)
|
||||
pkey = paramiko.ECDSAKey.from_private_key(p_file)
|
||||
except:
|
||||
p_file.seek(0)
|
||||
pkey = paramiko.DSSKey.from_private_key(p_file)
|
||||
|
||||
self.__tp.auth_publickey(username=self.__user, key=pkey)
|
||||
else:
|
||||
try:
|
||||
self.__tp.auth_none(self.__user)
|
||||
except Exception as e:
|
||||
e = str(e)
|
||||
if e.find('keyboard-interactive') >= 0:
|
||||
self._auth_interactive()
|
||||
else:
|
||||
self.debug('正在认证密码')
|
||||
self.__tp.auth_password(
|
||||
username=self.__user, password=self.__pass)
|
||||
except Exception as e:
|
||||
self.setSshdConfig(True)
|
||||
self.__tp.close()
|
||||
e = str(e)
|
||||
# print(e)
|
||||
if e.find('Authentication timeout') != -1:
|
||||
self.debug("认证超时{}".format(e))
|
||||
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
|
||||
if e.find('Authentication failed') != -1:
|
||||
self.debug('认证失败{}'.format(e))
|
||||
return self.returnMsg(False, '帐号或密码错误: {}'.format(e + "," + self.__user + "@" + self.__host + ":" + str(self.__port)))
|
||||
if e.find('Bad authentication type; allowed types') != -1:
|
||||
self.debug('认证失败{}'.format(e))
|
||||
if self.__host in ['127.0.0.1', 'localhost'] and self.__pass == 'none':
|
||||
return self.returnMsg(False, '帐号或密码错误: {}'.format("Authentication failed ," + self.__user + "@" + self.__host + ":" + str(self.__port)))
|
||||
return self.returnMsg(False, '不支持的身份验证类型: {}'.format(e))
|
||||
if e.find('Connection reset by peer') != -1:
|
||||
self.debug('目标服务器主动拒绝连接')
|
||||
return self.returnMsg(False, '目标服务器主动拒绝连接')
|
||||
if e.find('Error reading SSH protocol banner') != -1:
|
||||
self.debug('协议头响应超时')
|
||||
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
|
||||
if not e:
|
||||
self.debug('SSH协议握手超时')
|
||||
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
|
||||
err = mw.getTracebackInfo()
|
||||
self.debug(err)
|
||||
return self.returnMsg(False, "未知错误: {}".format(err))
|
||||
|
||||
self.debug('认证成功,正在构建会话通道')
|
||||
|
||||
ssh = self.__tp.open_session()
|
||||
ssh.get_pty(term='xterm', width=100, height=34)
|
||||
ssh.invoke_shell()
|
||||
self.__ssh_list[sid] = ssh
|
||||
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
|
||||
self.__host, self.__port))
|
||||
self.debug('通道已构建')
|
||||
return self.returnMsg(True, '连接成功.')
|
||||
|
||||
def getSshInfo(self, file):
|
||||
rdata = mw.readFile(file)
|
||||
destr = mw.enDoubleCrypt('mdserver-web', rdata)
|
||||
return json.loads(destr)
|
||||
|
||||
def setAttr(self, sid, info):
|
||||
self.__host = info['host'].strip()
|
||||
|
||||
# 外部连接获取
|
||||
if not self.__host in ['127.0.0.1', 'localhost']:
|
||||
dst_info = mw.getServerDir() + '/webssh/host/' + self.__host + '/info.json'
|
||||
if os.path.exists(dst_info):
|
||||
info = self.getSshInfo(dst_info)
|
||||
|
||||
if 'type' in info:
|
||||
self.__type = info['type']
|
||||
|
||||
if 'port' in info:
|
||||
self.__port = int(info['port'])
|
||||
if 'username' in info:
|
||||
self.__user = info['username']
|
||||
if 'pkey' in info:
|
||||
self.__pkey = info['pkey']
|
||||
if 'password' in info:
|
||||
self.__pass = info['password']
|
||||
if 'pkey_passwd' in info:
|
||||
self.__key_passwd = info['pkey_passwd']
|
||||
|
||||
# print(self.__host, self.__pass, self.__key_passwd)
|
||||
try:
|
||||
result = self.connect(sid)
|
||||
# print(result)
|
||||
except Exception as ex:
|
||||
if str(ex).find("NoneType") == -1:
|
||||
raise ex
|
||||
return result
|
||||
|
||||
def send(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
if self.__ssh:
|
||||
self.__ssh.close()
|
||||
if self.__tp: # 关闭宿主服务
|
||||
self.__tp.close()
|
||||
if self.__ps:
|
||||
self.__ps.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def resize(self, sid, data):
|
||||
try:
|
||||
self.__ssh_list[sid].resize_pty(
|
||||
width=data['cols'], height=data['rows'])
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def wsSend(self, recv):
|
||||
try:
|
||||
t = recv.decode("utf-8")
|
||||
return emit('server_response', {'data': t})
|
||||
except Exception as e:
|
||||
return emit('server_response', {'data': recv})
|
||||
|
||||
def wsSendConnect(self):
|
||||
return emit('connect', {'data': 'ok'})
|
||||
|
||||
def wsSendReConnect(self):
|
||||
return emit('reconnect', {'data': 'ok'})
|
||||
|
||||
def heartbeat(self):
|
||||
# limit_cos = 10
|
||||
while True:
|
||||
time.sleep(3)
|
||||
cur_time = time.time()
|
||||
for x in list(self.__ssh_list.keys()):
|
||||
ssh_last_time = self.__ssh_last_request_time[x]
|
||||
sid_off_cos = cur_time - ssh_last_time
|
||||
|
||||
# print("heartbeat off cos :", x, sid_off_cos)
|
||||
if sid_off_cos > 3:
|
||||
cur_ssh = self.__ssh_list[x]
|
||||
if not cur_ssh:
|
||||
del(self.__ssh_list[x])
|
||||
del(self.__ssh_last_request_time[x])
|
||||
continue
|
||||
|
||||
if cur_ssh.exit_status_ready():
|
||||
del(self.__ssh_list[x])
|
||||
del(self.__ssh_last_request_time[x])
|
||||
continue
|
||||
|
||||
cur_ssh.send("exit\r\n")
|
||||
del(self.__ssh_list[x])
|
||||
del(self.__ssh_last_request_time[x])
|
||||
|
||||
def run(self, sid, info):
|
||||
self.__sid = sid
|
||||
if not self.__sid:
|
||||
return self.wsSend('WebSocketIO无效')
|
||||
|
||||
self.__ssh_last_request_time[sid] = time.time()
|
||||
if not sid in self.__ssh_list:
|
||||
if type(info) == dict and 'host' in info:
|
||||
result = self.setAttr(sid, info)
|
||||
if result['status']:
|
||||
return self.wsSendConnect()
|
||||
else:
|
||||
return self.wsSend(result['msg'])
|
||||
else:
|
||||
return self.wsSendReConnect()
|
||||
|
||||
result = self.returnMsg(False, '')
|
||||
if sid in self.__ssh_list:
|
||||
if 'resize' in info:
|
||||
self.resize(sid, info)
|
||||
result = self.returnMsg(True, '已连接')
|
||||
if result['status']:
|
||||
if type(info) == str:
|
||||
time.sleep(0.1)
|
||||
cur_ssh = self.__ssh_list[sid]
|
||||
if cur_ssh.exit_status_ready():
|
||||
self.wsSend("logout\r\n")
|
||||
del(self.__ssh_list[sid])
|
||||
return
|
||||
cur_ssh.send(info)
|
||||
try:
|
||||
time.sleep(0.005)
|
||||
recv = cur_ssh.recv(8192)
|
||||
return self.wsSend(recv)
|
||||
except Exception as ex:
|
||||
return self.wsSend('')
|
||||
else:
|
||||
return self.wsSend(result['msg'])
|
||||
+151
-434
@@ -1,44 +1,16 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 系统信息操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import re
|
||||
import math
|
||||
import sys
|
||||
import json
|
||||
|
||||
from flask import Flask, session
|
||||
from flask import request
|
||||
|
||||
import db
|
||||
import mw
|
||||
|
||||
import config_api
|
||||
import requests
|
||||
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
|
||||
def mw_async(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
thr = Thread(target=f, args=args, kwargs=kwargs)
|
||||
thr.start()
|
||||
return wrapper
|
||||
import public
|
||||
|
||||
|
||||
class system_api:
|
||||
@@ -46,91 +18,7 @@ class system_api:
|
||||
pids = None
|
||||
|
||||
def __init__(self):
|
||||
self.setupPath = mw.getServerDir()
|
||||
|
||||
##### ----- start ----- ###
|
||||
def networkApi(self):
|
||||
data = self.getNetWork()
|
||||
return mw.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 mw.getJson(data)
|
||||
|
||||
def diskInfoApi(self):
|
||||
diskInfo = self.getDiskInfo()
|
||||
return mw.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 mw.getJson(data)
|
||||
|
||||
def getCpuIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getCpuIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getDiskIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getDiskIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getNetworkIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getNetWorkIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def rememoryApi(self):
|
||||
os.system('sync')
|
||||
scriptFile = mw.getRunDir() + '/script/rememory.sh'
|
||||
mw.execShell("/bin/bash " + scriptFile)
|
||||
data = self.getMemInfo()
|
||||
return mw.getJson(data)
|
||||
|
||||
# 重启面板
|
||||
def restartApi(self):
|
||||
self.restartMw()
|
||||
return mw.returnJson(True, '面板已重启!')
|
||||
|
||||
def restartServerApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(False, "开发环境不可重起")
|
||||
self.restartServer()
|
||||
return mw.returnJson(True, '正在重启服务器!')
|
||||
##### ----- end ----- ###
|
||||
|
||||
def restartTask(self):
|
||||
initd = mw.getRunDir() + '/scripts/init.d/mw'
|
||||
if os.path.exists(initd):
|
||||
os.system(initd + ' ' + 'restart_task')
|
||||
return True
|
||||
|
||||
def restartMw(self):
|
||||
mw.writeFile('data/restart.pl', 'True')
|
||||
return True
|
||||
|
||||
@mw_async
|
||||
def restartServer(self):
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
|
||||
mw.execShell("sync && init 6 &")
|
||||
return mw.returnJson(True, '命令发送成功!')
|
||||
self.setupPath = '/www/server'
|
||||
|
||||
# 名取PID
|
||||
def getPid(self, pname):
|
||||
@@ -166,59 +54,32 @@ class system_api:
|
||||
except:
|
||||
return False
|
||||
|
||||
def getEnvInfoApi(self, get=None):
|
||||
serverInfo = {}
|
||||
serverInfo['status'] = True
|
||||
sdir = mw.getServerDir()
|
||||
|
||||
serverInfo['webserver'] = '未安装'
|
||||
if os.path.exists(sdir + '/openresty/nginx/sbin/nginx'):
|
||||
serverInfo['webserver'] = 'OpenResty'
|
||||
serverInfo['php'] = []
|
||||
phpversions = ['52', '53', '54', '55', '56', '70', '71',
|
||||
'72', '73', '74', '80', '81', '82', '83', '84']
|
||||
phpPath = sdir + '/php/'
|
||||
for pv in phpversions:
|
||||
if not os.path.exists(phpPath + pv + '/bin/php'):
|
||||
continue
|
||||
serverInfo['php'].append(pv)
|
||||
serverInfo['mysql'] = False
|
||||
if os.path.exists(sdir + '/mysql/bin/mysql'):
|
||||
serverInfo['mysql'] = True
|
||||
import psutil
|
||||
try:
|
||||
diskInfo = psutil.disk_usage('/www')
|
||||
except:
|
||||
diskInfo = psutil.disk_usage('/')
|
||||
serverInfo['disk'] = diskInfo[2]
|
||||
return mw.returnJson(True, 'ok', serverInfo)
|
||||
|
||||
def getPanelInfo(self, get=None):
|
||||
# 取面板配置
|
||||
address = mw.GetLocalIp()
|
||||
address = public.GetLocalIp()
|
||||
try:
|
||||
try:
|
||||
port = web.ctx.host.split(':')[1]
|
||||
except:
|
||||
port = mw.readFile('data/port.pl')
|
||||
port = public.readFile('data/port.pl')
|
||||
except:
|
||||
port = '7200'
|
||||
port = '8888'
|
||||
domain = ''
|
||||
if os.path.exists('data/domain.conf'):
|
||||
domain = mw.readFile('data/domain.conf')
|
||||
domain = public.readFile('data/domain.conf')
|
||||
|
||||
autoUpdate = ''
|
||||
if os.path.exists('data/autoUpdate.pl'):
|
||||
autoUpdate = 'checked'
|
||||
limitip = ''
|
||||
if os.path.exists('data/limitip.conf'):
|
||||
limitip = mw.readFile('data/limitip.conf')
|
||||
limitip = public.readFile('data/limitip.conf')
|
||||
|
||||
templates = []
|
||||
for template in os.listdir('templates/'):
|
||||
if os.path.isdir('templates/' + template):
|
||||
templates.append(template)
|
||||
template = mw.readFile('data/templates.pl')
|
||||
template = public.readFile('data/templates.pl')
|
||||
|
||||
check502 = ''
|
||||
if os.path.exists('data/502Task.pl'):
|
||||
@@ -233,17 +94,17 @@ class system_api:
|
||||
data['cpuRealUsed'] = cpu[0]
|
||||
data['time'] = self.getBootTime()
|
||||
data['system'] = self.getSystemVersion()
|
||||
data['isuser'] = mw.M('users').where(
|
||||
data['isuser'] = public.M('users').where(
|
||||
'username=?', ('admin',)).count()
|
||||
data['version'] = '0.0.1'
|
||||
return data
|
||||
|
||||
def getLoadAverage(self):
|
||||
def getLoadAverage(self, get=None):
|
||||
c = os.getloadavg()
|
||||
data = {}
|
||||
data['one'] = round(float(c[0]), 2)
|
||||
data['five'] = round(float(c[1]), 2)
|
||||
data['fifteen'] = round(float(c[2]), 2)
|
||||
data['one'] = float(c[0])
|
||||
data['five'] = float(c[1])
|
||||
data['fifteen'] = float(c[2])
|
||||
data['max'] = psutil.cpu_count() * 2
|
||||
data['limit'] = data['max']
|
||||
data['safe'] = data['max'] * 0.75
|
||||
@@ -255,7 +116,7 @@ class system_api:
|
||||
data['title'] = self.GetTitle()
|
||||
data['network'] = self.GetNetWorkApi(get)
|
||||
data['panel_status'] = not os.path.exists(
|
||||
'/www/server/mdserver-web/data/close.pl')
|
||||
'/www/server/panel/data/close.pl')
|
||||
import firewalls
|
||||
ssh_info = firewalls.firewalls().GetSshInfo(None)
|
||||
data['enable_ssh_status'] = ssh_info['status']
|
||||
@@ -268,114 +129,63 @@ class system_api:
|
||||
|
||||
def getTitle(self):
|
||||
titlePl = 'data/title.pl'
|
||||
title = 'Linux面板'
|
||||
title = '宝塔Linux面板'
|
||||
if os.path.exists(titlePl):
|
||||
title = mw.readFile(titlePl).strip()
|
||||
title = public.readFile(titlePl).strip()
|
||||
return title
|
||||
|
||||
def getSystemDeviceTemperature(self):
|
||||
if not hasattr(psutil, "sensors_temperatures"):
|
||||
return False, "platform not supported"
|
||||
temps = psutil.sensors_temperatures()
|
||||
if not temps:
|
||||
return False, "can't read any temperature"
|
||||
for name, entries in temps.items():
|
||||
for entry in entries:
|
||||
return True, entry.label
|
||||
# print("%-20s %s °C (high = %s °C, critical = %s °C)" % (
|
||||
# entry.label or name, entry.current, entry.high,
|
||||
# entry.critical))
|
||||
return False, ""
|
||||
|
||||
def getSystemVersion(self):
|
||||
#
|
||||
# 取操作系统版本
|
||||
current_os = mw.getOs()
|
||||
# sys_temper = self.getSystemDeviceTemperature()
|
||||
# print(sys_temper)
|
||||
# mac
|
||||
if current_os == 'darwin':
|
||||
data = mw.execShell('sw_vers')[0]
|
||||
os = public.getOs()
|
||||
if os == 'darwin':
|
||||
data = public.execShell('sw_vers')[0]
|
||||
data_list = data.strip().split("\n")
|
||||
mac_version = ''
|
||||
for x in data_list:
|
||||
xlist = x.split("\t")
|
||||
mac_version += xlist[len(xlist)-1] + ' '
|
||||
mac_version += x.split("\t")[1] + ' '
|
||||
return mac_version
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return mac_version + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
# freebsd
|
||||
if current_os.startswith('freebsd'):
|
||||
version = mw.execShell(
|
||||
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
|
||||
arch_ver = mw.execShell(
|
||||
"sysctl -a | egrep -i 'hw.machine_arch' | awk -F ':' '{print $2}'")
|
||||
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
redhat_series = '/etc/redhat-release'
|
||||
if os.path.exists(redhat_series):
|
||||
version = mw.readFile('/etc/redhat-release')
|
||||
version = public.readFile('/etc/redhat-release')
|
||||
if not version:
|
||||
version = public.readFile(
|
||||
'/etc/issue').strip().split("\n")[0].replace('\\n', '').replace('\l', '').strip()
|
||||
else:
|
||||
version = version.replace('release ', '').strip()
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return version + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
os_series = '/etc/os-release'
|
||||
if os.path.exists(os_series):
|
||||
version = mw.execShell(
|
||||
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
return '未识别系统信息'
|
||||
return version
|
||||
|
||||
def getBootTime(self):
|
||||
# 取系统启动时间
|
||||
uptime = mw.readFile('/proc/uptime')
|
||||
if uptime == False:
|
||||
start_time = psutil.boot_time()
|
||||
run_time = time.time() - start_time
|
||||
else:
|
||||
run_time = uptime.split()[0]
|
||||
# conf = public.readFile('/proc/uptime').split()
|
||||
tStr = float(run_time)
|
||||
min = tStr / 60
|
||||
hours = min / 60
|
||||
days = math.floor(hours / 24)
|
||||
hours = math.floor(hours - (days * 24))
|
||||
min = math.floor(min - (days * 60 * 24) - (hours * 60))
|
||||
return mw.getInfo('已不间断运行: {1}天{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
|
||||
return public.getInfo('已不间断运行: {1}天{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
|
||||
|
||||
def getCpuInfo(self, interval=1):
|
||||
# 取CPU信息
|
||||
cpuCount = psutil.cpu_count()
|
||||
cpuLogicalNum = psutil.cpu_count(logical=False)
|
||||
used = psutil.cpu_percent(interval=interval)
|
||||
cpuLogicalNum = 0
|
||||
if os.path.exists('/proc/cpuinfo'):
|
||||
c_tmp = mw.readFile('/proc/cpuinfo')
|
||||
d_tmp = re.findall("physical id.+", c_tmp)
|
||||
cpuLogicalNum = len(set(d_tmp))
|
||||
return used, cpuCount
|
||||
|
||||
used_all = psutil.cpu_percent(percpu=True)
|
||||
cpu_name = mw.getCpuType() + " * {}".format(cpuLogicalNum)
|
||||
return used, cpuCount, used_all, cpu_name, cpuCount, cpuLogicalNum
|
||||
|
||||
def getMemInfo(self):
|
||||
def getMemInfo(self, get=None):
|
||||
# 取内存信息
|
||||
mem = psutil.virtual_memory()
|
||||
if mw.getOs() == 'darwin':
|
||||
if public.getOs() == 'darwin':
|
||||
memInfo = {
|
||||
'memTotal': mem.total,
|
||||
'memTotal': mem.total / 1024 / 1024
|
||||
}
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
|
||||
else:
|
||||
memInfo = {
|
||||
'memTotal': mem.total,
|
||||
'memFree': mem.free,
|
||||
'memBuffers': mem.buffers,
|
||||
'memCached': mem.cached
|
||||
'memTotal': mem.total / 1024 / 1024,
|
||||
'memFree': mem.free / 1024 / 1024,
|
||||
'memBuffers': mem.buffers / 1024 / 1024,
|
||||
'memCached': mem.cached / 1024 / 1024
|
||||
}
|
||||
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] - \
|
||||
@@ -389,7 +199,7 @@ class system_api:
|
||||
import psutil
|
||||
mem = psutil.virtual_memory()
|
||||
|
||||
if mw.getOs() == 'darwin':
|
||||
if public.getOs() == 'darwin':
|
||||
return mem.percent
|
||||
|
||||
memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024,
|
||||
@@ -398,14 +208,11 @@ class system_api:
|
||||
memInfo['memBuffers'] - memInfo['memCached']
|
||||
tmp1 = memInfo['memTotal'] / 100
|
||||
return (tmp / tmp1)
|
||||
except Exception as ex:
|
||||
except Exception, ex:
|
||||
return 1
|
||||
|
||||
def getDiskInfo(self):
|
||||
info = self.getDiskInfo2()
|
||||
if len(info) != 0:
|
||||
return info
|
||||
|
||||
def getDiskInfo(self, get=None):
|
||||
return self.getDiskInfo2()
|
||||
# 取磁盘分区信息
|
||||
diskIo = psutil.disk_partitions()
|
||||
diskInfo = []
|
||||
@@ -417,24 +224,22 @@ class system_api:
|
||||
continue
|
||||
tmp = {}
|
||||
tmp['path'] = disk[1]
|
||||
size_tmp = psutil.disk_usage(disk[1])
|
||||
tmp['size'] = [mw.toSize(size_tmp[0]), mw.toSize(
|
||||
size_tmp[1]), mw.toSize(size_tmp[2]), str(size_tmp[3]) + '%']
|
||||
tmp['size'] = psutil.disk_usage(disk[1])
|
||||
diskInfo.append(tmp)
|
||||
return diskInfo
|
||||
|
||||
def getDiskInfo2(self):
|
||||
# 取磁盘分区信息
|
||||
temp = mw.execShell(
|
||||
temp = public.execShell(
|
||||
"df -h -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
|
||||
tempInodes = mw.execShell(
|
||||
tempInodes = public.execShell(
|
||||
"df -i -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
|
||||
temp1 = temp.split('\n')
|
||||
tempInodes1 = tempInodes.split('\n')
|
||||
diskInfo = []
|
||||
n = 0
|
||||
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev',
|
||||
'/dev/shm', '/zroot', '/run/lock', '/run', '/run/shm', '/run/user']
|
||||
'/dev/shm', '/run/lock', '/run', '/run/shm', '/run/user']
|
||||
for tmp in temp1:
|
||||
n += 1
|
||||
inodes = tempInodes1[n - 1].split()
|
||||
@@ -454,6 +259,15 @@ class system_api:
|
||||
tmp1 = [disk[1], disk[2], disk[3], disk[4]]
|
||||
arr['size'] = tmp1
|
||||
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
|
||||
if disk[5] == '/':
|
||||
bootLog = os.getcwd() + '/tmp/panelBoot.pl'
|
||||
if disk[2].find('M') != -1:
|
||||
if os.path.exists(bootLog):
|
||||
os.system('rm -f ' + bootLog)
|
||||
else:
|
||||
if not os.path.exists(bootLog):
|
||||
pass
|
||||
if inodes[2] != '0':
|
||||
diskInfo.append(arr)
|
||||
return diskInfo
|
||||
|
||||
@@ -488,7 +302,7 @@ class system_api:
|
||||
shutil.rmtree(filename)
|
||||
else:
|
||||
os.remove(filename)
|
||||
print('mail clear ok')
|
||||
print '\t\033[1;32m[OK]\033[0m'
|
||||
num += 1
|
||||
total += size
|
||||
count += num
|
||||
@@ -497,10 +311,10 @@ class system_api:
|
||||
# 清理其它
|
||||
def clearOther(self):
|
||||
clearPath = [
|
||||
{'path': '/www/server/mdserver-web', 'find': 'testDisk_'},
|
||||
{'path': '/www/server/panel', 'find': 'testDisk_'},
|
||||
{'path': '/www/wwwlogs', 'find': 'log'},
|
||||
{'path': '/tmp', 'find': 'panelBoot.pl'},
|
||||
{'path': '/www/server/mdserver-web/install', 'find': '.rpm'}
|
||||
{'path': '/www/server/panel/install', 'find': '.rpm'}
|
||||
]
|
||||
|
||||
total = count = 0
|
||||
@@ -516,39 +330,16 @@ class system_api:
|
||||
else:
|
||||
os.remove(filename)
|
||||
count += 1
|
||||
mw.restartWeb()
|
||||
public.serviceReload()
|
||||
os.system('echo > /tmp/panelBoot.pl')
|
||||
return total, count
|
||||
|
||||
def psutilNetIoCounters(self):
|
||||
'''
|
||||
统计网卡流量
|
||||
'''
|
||||
stat_pl = 'data/only_netio_counters.pl'
|
||||
if os.path.exists(stat_pl):
|
||||
local_lo = (0, 0, 0, 0)
|
||||
ioName = psutil.net_io_counters(pernic=True).keys()
|
||||
for x in ioName:
|
||||
|
||||
if x.find("lo") > -1:
|
||||
local_lo = psutil.net_io_counters(
|
||||
pernic=True).get(x)[:4]
|
||||
|
||||
all_io = psutil.net_io_counters()[:4]
|
||||
result_io = tuple([all_io[i] - local_lo[i]
|
||||
for i in range(0, len(all_io))])
|
||||
|
||||
# print(local_lo)
|
||||
# print(all_io)
|
||||
# print(result_io)
|
||||
return result_io
|
||||
return psutil.net_io_counters()[:4]
|
||||
|
||||
def getNetWork(self):
|
||||
def getNetWork(self, get=None):
|
||||
# return self.GetNetWorkApi(get);
|
||||
# 取网络流量信息
|
||||
try:
|
||||
# 取网络流量信息
|
||||
networkIo = self.psutilNetIoCounters()
|
||||
networkIo = psutil.net_io_counters()[:4]
|
||||
if not "otime" in session:
|
||||
session['up'] = networkIo[0]
|
||||
session['down'] = networkIo[1]
|
||||
@@ -559,9 +350,9 @@ class system_api:
|
||||
networkInfo['upTotal'] = networkIo[0]
|
||||
networkInfo['downTotal'] = networkIo[1]
|
||||
networkInfo['up'] = round(float(
|
||||
networkIo[0] - session['up']) / (ntime - session['otime']), 2)
|
||||
networkIo[0] - session['up']) / 1024 / (ntime - session['otime']), 2)
|
||||
networkInfo['down'] = round(
|
||||
float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
|
||||
float(networkIo[1] - session['down']) / 1024 / (ntime - session['otime']), 2)
|
||||
networkInfo['downPackets'] = networkIo[3]
|
||||
networkInfo['upPackets'] = networkIo[2]
|
||||
|
||||
@@ -571,34 +362,82 @@ class system_api:
|
||||
session['otime'] = time.time()
|
||||
|
||||
networkInfo['cpu'] = self.getCpuInfo()
|
||||
networkInfo['load'] = self.getLoadAverage()
|
||||
networkInfo['mem'] = self.getMemInfo()
|
||||
networkInfo['load'] = self.getLoadAverage(get)
|
||||
networkInfo['mem'] = self.getMemInfo(get)
|
||||
|
||||
return networkInfo
|
||||
except Exception as e:
|
||||
print("getNetWork error:", e)
|
||||
except Exception, e:
|
||||
print e
|
||||
return None
|
||||
|
||||
def getNetWorkApi(self, get=None):
|
||||
# 取网络流量信息
|
||||
try:
|
||||
tmpfile = 'data/network.temp'
|
||||
networkIo = psutil.net_io_counters()[:4]
|
||||
|
||||
if not os.path.exists(tmpfile):
|
||||
public.writeFile(tmpfile, str(
|
||||
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
|
||||
|
||||
lastValue = public.readFile(tmpfile).split('|')
|
||||
|
||||
ntime = time.time()
|
||||
networkInfo = {}
|
||||
networkInfo['upTotal'] = networkIo[0]
|
||||
networkInfo['downTotal'] = networkIo[1]
|
||||
networkInfo['up'] = round(
|
||||
float(networkIo[0] - int(lastValue[0])) / 1024 / (ntime - int(lastValue[2])), 2)
|
||||
networkInfo['down'] = round(
|
||||
float(networkIo[1] - int(lastValue[1])) / 1024 / (ntime - int(lastValue[2])), 2)
|
||||
networkInfo['downPackets'] = networkIo[3]
|
||||
networkInfo['upPackets'] = networkIo[2]
|
||||
|
||||
public.writeFile(tmpfile, str(
|
||||
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
|
||||
|
||||
# networkInfo['cpu'] = self.GetCpuInfo(0.1)
|
||||
return networkInfo
|
||||
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 = mw.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
data = public.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
'id,up,down,total_up,total_down,down_packets,up_packets,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
def getDiskIoData(self, start, end):
|
||||
# 取指定时间段的磁盘Io
|
||||
data = mw.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
data = public.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
'id,read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
def getCpuIoData(self, start, end):
|
||||
# 取指定时间段的CpuIo
|
||||
data = mw.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",
|
||||
data = public.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",
|
||||
(start, end)).field('id,pro,mem,addtime').order('id asc').select()
|
||||
return self.toAddtime(data, True)
|
||||
|
||||
def getLoadAverageData(self, start, end):
|
||||
data = mw.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (
|
||||
data = public.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (
|
||||
start, end)).field('id,pro,one,five,fifteen,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
@@ -642,194 +481,72 @@ class system_api:
|
||||
def setControl(self, stype, day):
|
||||
|
||||
filename = 'data/control.conf'
|
||||
stat_pl = 'data/only_netio_counters.pl'
|
||||
|
||||
if stype == '0':
|
||||
mw.execShell("rm -rf " + filename)
|
||||
public.execShell("rm -f " + filename)
|
||||
elif stype == '1':
|
||||
_day = int(day)
|
||||
if _day < 1:
|
||||
return mw.returnJson(False, "设置失败!")
|
||||
mw.writeFile(filename, day)
|
||||
elif stype == '2':
|
||||
mw.execShell("rm -rf " + stat_pl)
|
||||
elif stype == '3':
|
||||
mw.execShell("echo 'True' > " + stat_pl)
|
||||
return public.returnJson(False, "设置失败!")
|
||||
public.writeFile(filename, day)
|
||||
elif stype == 'del':
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行')
|
||||
if not public.isRestart():
|
||||
return public.returnJson(False, '请等待所有安装任务完成再执行')
|
||||
os.remove("data/system.db")
|
||||
|
||||
sql = db.Sql().dbfile('system')
|
||||
csql = mw.readFile('data/sql/system.sql')
|
||||
csql = public.readFile('data/sql/system.sql')
|
||||
csql_list = csql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
sql.execute(csql_list[index], ())
|
||||
return mw.returnJson(True, "监控服务已关闭")
|
||||
return public.returnJson(True, "监控服务已关闭")
|
||||
else:
|
||||
data = {}
|
||||
if os.path.exists(filename):
|
||||
try:
|
||||
data['day'] = int(mw.readFile(filename))
|
||||
data['day'] = int(public.readFile(filename))
|
||||
except:
|
||||
data['day'] = 30
|
||||
data['status'] = True
|
||||
else:
|
||||
data['day'] = 30
|
||||
data['status'] = False
|
||||
return public.getJson(data)
|
||||
|
||||
if os.path.exists(stat_pl):
|
||||
data['stat_all_status'] = True
|
||||
else:
|
||||
data['stat_all_status'] = False
|
||||
return public.returnJson(True, "设置成功!")
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
return mw.returnJson(True, "设置成功!")
|
||||
|
||||
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'
|
||||
|
||||
isHasNew = True
|
||||
if int(new_list[0]) == int(old_list[0]) and int(new_list[1]) == int(old_list[1]) and int(new_list[2]) == int(old_list[2]):
|
||||
isHasNew = False
|
||||
|
||||
if isHasNew:
|
||||
return 'new'
|
||||
return ret
|
||||
|
||||
def getServerInfo(self):
|
||||
import urllib.request
|
||||
import ssl
|
||||
upAddr = 'https://api.github.com/repos/midoks/mdserver-web/releases/latest'
|
||||
try:
|
||||
context = ssl._create_unverified_context()
|
||||
req = urllib.request.urlopen(upAddr, context=context, timeout=3)
|
||||
result = req.read().decode('utf-8')
|
||||
version = json.loads(result)
|
||||
return version
|
||||
except Exception as e:
|
||||
print('getServerInfo', e)
|
||||
return {}
|
||||
|
||||
def updateServer(self, stype, version=''):
|
||||
# 更新服务
|
||||
def updateServer(self, stype):
|
||||
try:
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
|
||||
|
||||
version_new_info = self.getServerInfo()
|
||||
version_now = config_api.config_api().getVersion()
|
||||
|
||||
new_ver = version_new_info['name']
|
||||
|
||||
if not public.isRestart():
|
||||
return public.returnMsg(False, '请等待所有安装任务完成再执行!')
|
||||
if stype == 'check':
|
||||
if not 'name' in version_new_info:
|
||||
return mw.returnJson(False, '服务器数据或网络有问题!')
|
||||
|
||||
diff = self.versionDiff(version_now, new_ver)
|
||||
if diff == 'new':
|
||||
return mw.returnJson(True, '有新版本!', new_ver)
|
||||
elif diff == 'test':
|
||||
return mw.returnJson(True, '有测试版本!', new_ver)
|
||||
else:
|
||||
return mw.returnJson(False, '已经是最新,无需更新!')
|
||||
|
||||
if stype == 'info':
|
||||
if not 'name' in version_new_info:
|
||||
return mw.returnJson(False, '服务器数据有问题!')
|
||||
diff = self.versionDiff(version_now, new_ver)
|
||||
data = {}
|
||||
data['version'] = new_ver
|
||||
data['content'] = version_new_info[
|
||||
'body'].replace("\n", "<br/>")
|
||||
return mw.returnJson(True, '更新信息!', data)
|
||||
|
||||
if stype == 'update':
|
||||
if version == '':
|
||||
return mw.returnJson(False, '缺少版本信息!')
|
||||
|
||||
if new_ver != version:
|
||||
return mw.returnJson(False, '更新失败,请重试!')
|
||||
|
||||
toPath = mw.getRootDir() + '/temp'
|
||||
if not os.path.exists(toPath):
|
||||
mw.execShell('mkdir -p ' + toPath)
|
||||
|
||||
newUrl = "https://github.com/midoks/mdserver-web/archive/refs/tags/" + version + ".zip"
|
||||
|
||||
dist_mw = toPath + '/mw.zip'
|
||||
if not os.path.exists(dist_mw):
|
||||
mw.execShell(
|
||||
'wget --no-check-certificate -O ' + dist_mw + ' ' + newUrl)
|
||||
|
||||
dist_to = toPath + "/mdserver-web-" + version
|
||||
if not os.path.exists(dist_to):
|
||||
os.system('unzip -o ' + toPath +
|
||||
'/mw.zip' + ' -d ' + toPath)
|
||||
|
||||
cmd_cp = 'cp -rf ' + toPath + '/mdserver-web-' + \
|
||||
version + '/* ' + mw.getServerDir() + '/mdserver-web'
|
||||
mw.execShell(cmd_cp)
|
||||
|
||||
mw.execShell('rm -rf ' + toPath + '/mdserver-web-' + version)
|
||||
mw.execShell('rm -rf ' + toPath + '/mw.zip')
|
||||
|
||||
update_env = '''
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
|
||||
P_VER=`python3 -V | awk '{print $2}'`
|
||||
|
||||
if [ ! -f /www/server/mdserver-web/bin/activate ];then
|
||||
cd /www/server/mdserver-web && python3 -m venv .
|
||||
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
|
||||
else
|
||||
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
|
||||
fi
|
||||
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
PIPSRC="https://pypi.python.org/simple"
|
||||
if [ ! -z "$cn" ];then
|
||||
PIPSRC="https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
fi
|
||||
|
||||
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/requirements.txt -i $PIPSRC
|
||||
|
||||
P_VER_D=`echo "$P_VER"|awk -F '.' '{print $1}'`
|
||||
P_VER_M=`echo "$P_VER"|awk -F '.' '{print $2}'`
|
||||
NEW_P_VER=${P_VER_D}.${P_VER_M}
|
||||
|
||||
if [ -f /www/server/mdserver-web/version/r${NEW_P_VER}.txt ];then
|
||||
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/version/r${NEW_P_VER}.txt -i $PIPSRC
|
||||
fi
|
||||
'''
|
||||
os.system(update_env)
|
||||
self.restartMw()
|
||||
return mw.returnJson(True, '安装更新成功!')
|
||||
|
||||
return mw.returnJson(False, '已经是最新,无需更新!')
|
||||
public.httpGet('')
|
||||
except Exception as ex:
|
||||
# print('updateServer', ex)
|
||||
return mw.returnJson(False, "连接服务器失败!" + str(ex))
|
||||
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
|
||||
|
||||
# 修复面板
|
||||
def repPanel(self, get):
|
||||
vp = ''
|
||||
if mw.readFile('/www/server/mdserver-web/class/common.py').find('checkSafe') != -1:
|
||||
if public.readFile('/www/server/panel/class/common.py').find('checkSafe') != -1:
|
||||
vp = '_pro'
|
||||
mw.ExecShell("wget -O update.sh " + mw.get_url() +
|
||||
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
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 任务页操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class task_api:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def countApi(self):
|
||||
c = mw.M('tasks').where("status!=?", ('1',)).count()
|
||||
return str(c)
|
||||
|
||||
def listApi(self):
|
||||
|
||||
p = request.form.get('p', '1')
|
||||
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 = mw.M('tasks').where('', ()).field(
|
||||
'id,name,type,status,addtime,start,end').limit(limit_str).order('id desc').select()
|
||||
_ret = {}
|
||||
_ret['data'] = _list
|
||||
|
||||
count = mw.M('tasks').where('', ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'remind'
|
||||
_page['p'] = p
|
||||
|
||||
# return data
|
||||
_ret['count'] = count
|
||||
_ret['page'] = mw.getPage(_page)
|
||||
return mw.getJson(_ret)
|
||||
|
||||
def getExecLogApi(self):
|
||||
file = os.getcwd() + "/tmp/panelExec.log"
|
||||
v = mw.getLastLine(file, 100)
|
||||
return v
|
||||
|
||||
def getTaskSpeedApi(self):
|
||||
tempFile = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
freshFile = mw.getRunDir() + '/tmp/panelFresh'
|
||||
|
||||
find = mw.M('tasks').where('status=? OR status=?',
|
||||
('-1', '0')).field('id,type,name,execstr').find()
|
||||
if not len(find):
|
||||
return mw.returnJson(False, '当前没有任务队列在执行-2!')
|
||||
|
||||
mw.triggerTask()
|
||||
|
||||
data = {}
|
||||
data['name'] = find['name']
|
||||
data['execstr'] = find['execstr']
|
||||
if find['type'] == 'download':
|
||||
readLine = ""
|
||||
for i in range(3):
|
||||
try:
|
||||
readLine = mw.readFile(tempFile)
|
||||
if len(readLine) > 10:
|
||||
data['msg'] = json.loads(readLine)
|
||||
data['isDownload'] = True
|
||||
break
|
||||
except Exception as e:
|
||||
if i == 2:
|
||||
mw.M('tasks').where("id=?", (find['id'],)).save(
|
||||
'status', ('0',))
|
||||
return mw.returnJson(False, '当前没有任务队列在执行-4:' + str(e))
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
data['msg'] = mw.getLastLine(tempFile, 10)
|
||||
data['isDownload'] = False
|
||||
|
||||
data['task'] = mw.M('tasks').where("status!=?", ('1',)).field(
|
||||
'id,status,name,type').order("id asc").select()
|
||||
return mw.getJson(data)
|
||||
+5
-16
@@ -1,17 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 验证码操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import random
|
||||
import math
|
||||
@@ -86,7 +75,7 @@ class vieCode:
|
||||
if not self.__inNoise:
|
||||
return
|
||||
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
|
||||
for i in range(5):
|
||||
for i in xrange(5):
|
||||
# 杂点颜色
|
||||
noiseColor = (random.randint(150, 200), random.randint(
|
||||
150, 200), random.randint(150, 200))
|
||||
@@ -115,9 +104,9 @@ class vieCode:
|
||||
# 画曲线
|
||||
color = (random.randint(30, 150), random.randint(
|
||||
30, 150), random.randint(30, 150))
|
||||
for x in range(xend):
|
||||
for x in xrange(xend):
|
||||
if w != 0:
|
||||
for k in range(int(self.__heigth / 10)):
|
||||
for k in xrange(int(self.__heigth / 10)):
|
||||
y = a * math.sin(w * x + f) + b + self.__heigth / 2
|
||||
i = int(self.__fontSize / 5)
|
||||
while i > 0:
|
||||
@@ -131,7 +120,7 @@ class vieCode:
|
||||
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
|
||||
x = 0
|
||||
# 打印字符到画板
|
||||
for i in range(self.__length):
|
||||
for i in xrange(self.__length):
|
||||
# 设置字体随机颜色
|
||||
color = (random.randint(30, 150), random.randint(
|
||||
30, 150), random.randint(30, 150))
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# VIP用户管理
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
import mw
|
||||
|
||||
from flask import request
|
||||
import requests
|
||||
|
||||
|
||||
class vip_api:
|
||||
|
||||
api_url = 'https://wo.midoks.icu/api/wp-json/vip'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def loginApi(self):
|
||||
username = request.form.get('username', '')
|
||||
password = request.form.get('password', '')
|
||||
password = mw.aesEncrypt(password)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}
|
||||
|
||||
print("name:", str(username))
|
||||
print("pwd:", str(password))
|
||||
args = {
|
||||
'name': username,
|
||||
'pass': password
|
||||
}
|
||||
data = requests.post(self.api_url + '/v1/login',
|
||||
data=args, headers=headers)
|
||||
|
||||
print(data.text)
|
||||
|
||||
return mw.returnJson(False, "测试中!")
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
- fcgi-client.py
|
||||
```
|
||||
https://pypi.org/project/flup6/1.1.1/#files
|
||||
```
|
||||
|
||||
@@ -1,408 +0,0 @@
|
||||
# Copyright (c) 2006 Allan Saddi <allan@saddi.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (c) 2011 Vladimir Rusinov <vladimir@greenmice.info>
|
||||
|
||||
__author__ = 'Allan Saddi <allan@saddi.com>'
|
||||
__version__ = '$Revision$'
|
||||
import sys
|
||||
import select
|
||||
import struct
|
||||
import socket
|
||||
import errno
|
||||
import types
|
||||
|
||||
|
||||
__all__ = ['FCGIApp']
|
||||
|
||||
# Constants from the spec.
|
||||
FCGI_LISTENSOCK_FILENO = 0
|
||||
|
||||
FCGI_HEADER_LEN = 8
|
||||
|
||||
FCGI_VERSION_1 = 1
|
||||
|
||||
FCGI_BEGIN_REQUEST = 1
|
||||
FCGI_ABORT_REQUEST = 2
|
||||
FCGI_END_REQUEST = 3
|
||||
FCGI_PARAMS = 4
|
||||
FCGI_STDIN = 5
|
||||
FCGI_STDOUT = 6
|
||||
FCGI_STDERR = 7
|
||||
FCGI_DATA = 8
|
||||
FCGI_GET_VALUES = 9
|
||||
FCGI_GET_VALUES_RESULT = 10
|
||||
FCGI_UNKNOWN_TYPE = 11
|
||||
FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
|
||||
|
||||
FCGI_NULL_REQUEST_ID = 0
|
||||
|
||||
FCGI_KEEP_CONN = 1
|
||||
|
||||
FCGI_RESPONDER = 1
|
||||
FCGI_AUTHORIZER = 2
|
||||
FCGI_FILTER = 3
|
||||
|
||||
FCGI_REQUEST_COMPLETE = 0
|
||||
FCGI_CANT_MPX_CONN = 1
|
||||
FCGI_OVERLOADED = 2
|
||||
FCGI_UNKNOWN_ROLE = 3
|
||||
|
||||
FCGI_MAX_CONNS = 'FCGI_MAX_CONNS'
|
||||
FCGI_MAX_REQS = 'FCGI_MAX_REQS'
|
||||
FCGI_MPXS_CONNS = 'FCGI_MPXS_CONNS'
|
||||
|
||||
FCGI_Header = '!BBHHBx'
|
||||
FCGI_BeginRequestBody = '!HB5x'
|
||||
FCGI_EndRequestBody = '!LB3x'
|
||||
FCGI_UnknownTypeBody = '!B7x'
|
||||
|
||||
FCGI_BeginRequestBody_LEN = struct.calcsize(FCGI_BeginRequestBody)
|
||||
FCGI_EndRequestBody_LEN = struct.calcsize(FCGI_EndRequestBody)
|
||||
FCGI_UnknownTypeBody_LEN = struct.calcsize(FCGI_UnknownTypeBody)
|
||||
|
||||
if __debug__:
|
||||
import time
|
||||
|
||||
# Set non-zero to write debug output to a file.
|
||||
DEBUG = 0
|
||||
DEBUGLOG = '/www/server/mdserver-web/logs/fastcgi.log'
|
||||
|
||||
def _debug(level, msg):
|
||||
if DEBUG < level:
|
||||
return
|
||||
|
||||
try:
|
||||
f = open(DEBUGLOG, 'a')
|
||||
f.write('%sfcgi: %s\n' % (time.ctime()[4:-4], msg))
|
||||
f.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def decode_pair(s, pos=0):
|
||||
"""
|
||||
Decodes a name/value pair.
|
||||
|
||||
The number of bytes decoded as well as the name/value pair
|
||||
are returned.
|
||||
"""
|
||||
nameLength = ord(s[pos])
|
||||
if nameLength & 128:
|
||||
nameLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
|
||||
pos += 4
|
||||
else:
|
||||
pos += 1
|
||||
|
||||
valueLength = ord(s[pos])
|
||||
if valueLength & 128:
|
||||
valueLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
|
||||
pos += 4
|
||||
else:
|
||||
pos += 1
|
||||
|
||||
name = s[pos:pos + nameLength]
|
||||
pos += nameLength
|
||||
value = s[pos:pos + valueLength]
|
||||
pos += valueLength
|
||||
|
||||
return (pos, (name, value))
|
||||
|
||||
|
||||
def encode_pair(name, value):
|
||||
"""
|
||||
Encodes a name/value pair.
|
||||
|
||||
The encoded string is returned.
|
||||
"""
|
||||
nameLength = len(name)
|
||||
if nameLength < 128:
|
||||
s = chr(nameLength).encode()
|
||||
else:
|
||||
s = struct.pack('!L', nameLength | 0x80000000)
|
||||
|
||||
valueLength = len(value)
|
||||
if valueLength < 128:
|
||||
s += chr(valueLength).encode()
|
||||
else:
|
||||
s += struct.pack('!L', valueLength | 0x80000000)
|
||||
|
||||
return s + name + value
|
||||
|
||||
|
||||
class Record(object):
|
||||
"""
|
||||
A FastCGI Record.
|
||||
|
||||
Used for encoding/decoding records.
|
||||
"""
|
||||
|
||||
def __init__(self, type=FCGI_UNKNOWN_TYPE, requestId=FCGI_NULL_REQUEST_ID):
|
||||
self.version = FCGI_VERSION_1
|
||||
self.type = type
|
||||
self.requestId = requestId
|
||||
self.contentLength = 0
|
||||
self.paddingLength = 0
|
||||
self.contentData = ''
|
||||
|
||||
def _recvall(sock, length):
|
||||
"""
|
||||
Attempts to receive length bytes from a socket, blocking if necessary.
|
||||
(Socket may be blocking or non-blocking.)
|
||||
"""
|
||||
dataList = []
|
||||
recvLen = 0
|
||||
while length:
|
||||
try:
|
||||
data = sock.recv(length)
|
||||
except socket.error as e:
|
||||
if e[0] == errno.EAGAIN:
|
||||
select.select([sock], [], [])
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
if not data: # EOF
|
||||
break
|
||||
dataList.append(data)
|
||||
dataLen = len(data)
|
||||
recvLen += dataLen
|
||||
length -= dataLen
|
||||
return b''.join(dataList), recvLen
|
||||
_recvall = staticmethod(_recvall)
|
||||
|
||||
def read(self, sock):
|
||||
"""Read and decode a Record from a socket."""
|
||||
try:
|
||||
header, length = self._recvall(sock, FCGI_HEADER_LEN)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
if length < FCGI_HEADER_LEN:
|
||||
raise EOFError
|
||||
|
||||
self.version, self.type, self.requestId, self.contentLength, \
|
||||
self.paddingLength = struct.unpack(FCGI_Header, header)
|
||||
|
||||
if __debug__:
|
||||
_debug(9, 'read: fd = %d, type = %d, requestId = %d, '
|
||||
'contentLength = %d' %
|
||||
(sock.fileno(), self.type, self.requestId,
|
||||
self.contentLength))
|
||||
|
||||
if self.contentLength:
|
||||
try:
|
||||
self.contentData, length = self._recvall(sock,
|
||||
self.contentLength)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
if length < self.contentLength:
|
||||
raise EOFError
|
||||
|
||||
if self.paddingLength:
|
||||
try:
|
||||
self._recvall(sock, self.paddingLength)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
def _sendall(sock, data):
|
||||
"""
|
||||
Writes data to a socket and does not return until all the data is sent.
|
||||
"""
|
||||
length = len(data)
|
||||
while length:
|
||||
try:
|
||||
sent = sock.send(data)
|
||||
except socket.error as e:
|
||||
if e[0] == errno.EAGAIN:
|
||||
select.select([], [sock], [])
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
data = data[sent:]
|
||||
length -= sent
|
||||
_sendall = staticmethod(_sendall)
|
||||
|
||||
def write(self, sock):
|
||||
"""Encode and write a Record to a socket."""
|
||||
self.paddingLength = -self.contentLength & 7
|
||||
|
||||
if __debug__:
|
||||
_debug(9, 'write: fd = %d, type = %d, requestId = %d, '
|
||||
'contentLength = %d' %
|
||||
(sock.fileno(), self.type, self.requestId,
|
||||
self.contentLength))
|
||||
|
||||
header = struct.pack(FCGI_Header, self.version, self.type,
|
||||
self.requestId, self.contentLength,
|
||||
self.paddingLength)
|
||||
self._sendall(sock, header)
|
||||
if self.contentLength:
|
||||
self._sendall(sock, self.contentData)
|
||||
if self.paddingLength:
|
||||
self._sendall(sock, b'\x00' * self.paddingLength)
|
||||
|
||||
|
||||
class FCGIApp(object):
|
||||
|
||||
def __init__(self, connect=None, host=None, port=None, filterEnviron=True):
|
||||
if host is not None:
|
||||
assert port is not None
|
||||
connect = (host, port)
|
||||
|
||||
self._connect = connect
|
||||
self._filterEnviron = filterEnviron
|
||||
|
||||
def __call__(self, environ, io, start_response=None):
|
||||
# For sanity's sake, we don't care about FCGI_MPXS_CONN
|
||||
# (connection multiplexing). For every request, we obtain a new
|
||||
# transport socket, perform the request, then discard the socket.
|
||||
# This is, I believe, how mod_fastcgi does things...
|
||||
|
||||
sock = self._getConnection()
|
||||
|
||||
# Since this is going to be the only request on this connection,
|
||||
# set the request ID to 1.
|
||||
requestId = 1
|
||||
|
||||
# Begin the request
|
||||
rec = Record(FCGI_BEGIN_REQUEST, requestId)
|
||||
rec.contentData = struct.pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0)
|
||||
rec.contentLength = FCGI_BeginRequestBody_LEN
|
||||
rec.write(sock)
|
||||
|
||||
# Filter WSGI environ and send it as FCGI_PARAMS
|
||||
if self._filterEnviron:
|
||||
params = self._defaultFilterEnviron(environ)
|
||||
else:
|
||||
params = self._lightFilterEnviron(environ)
|
||||
# TODO: Anything not from environ that needs to be sent also?
|
||||
# return '200 OK',[],str(params),''
|
||||
self._fcgiParams(sock, requestId, params)
|
||||
self._fcgiParams(sock, requestId, {})
|
||||
|
||||
# Transfer wsgi.input to FCGI_STDIN
|
||||
content_length = int(environ.get('CONTENT_LENGTH') or 0)
|
||||
s = ''
|
||||
#io = StringIO(stdin)
|
||||
while True:
|
||||
if not io:
|
||||
break
|
||||
chunk_size = min(content_length, 4096)
|
||||
s = io.read(chunk_size)
|
||||
content_length -= len(s)
|
||||
rec = Record(FCGI_STDIN, requestId)
|
||||
rec.contentData = s
|
||||
rec.contentLength = len(s)
|
||||
rec.write(sock)
|
||||
if not s:
|
||||
break
|
||||
# Empty FCGI_DATA stream
|
||||
rec = Record(FCGI_DATA, requestId)
|
||||
rec.write(sock)
|
||||
return sock
|
||||
|
||||
def _getConnection(self):
|
||||
if self._connect is not None:
|
||||
# The simple case. Create a socket and connect to the
|
||||
# application.
|
||||
if isinstance(self._connect, str):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.connect(self._connect)
|
||||
elif hasattr(socket, 'create_connection'):
|
||||
sock = socket.create_connection(self._connect)
|
||||
else:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect(self._connect)
|
||||
return sock
|
||||
|
||||
# To be done when I have more time...
|
||||
# , 'Launching and managing FastCGI programs not yet implemented'
|
||||
raise NotImplementedError
|
||||
|
||||
def _fcgiGetValues(self, sock, vars):
|
||||
# Construct FCGI_GET_VALUES record
|
||||
outrec = Record(FCGI_GET_VALUES)
|
||||
data = []
|
||||
for name in vars:
|
||||
data.append(encode_pair(name, ''))
|
||||
data = ''.join(data)
|
||||
outrec.contentData = data
|
||||
outrec.contentLength = len(data)
|
||||
outrec.write(sock)
|
||||
|
||||
# Await response
|
||||
inrec = Record()
|
||||
inrec.read(sock)
|
||||
result = {}
|
||||
if inrec.type == FCGI_GET_VALUES_RESULT:
|
||||
pos = 0
|
||||
while pos < inrec.contentLength:
|
||||
pos, (name, value) = decode_pair(inrec.contentData, pos)
|
||||
result[name] = value
|
||||
return result
|
||||
|
||||
def _fcgiParams(self, sock, requestId, params):
|
||||
rec = Record(FCGI_PARAMS, requestId)
|
||||
data = []
|
||||
for name, value in params.items():
|
||||
data.append(encode_pair(name.encode(
|
||||
'latin-1'), value.encode('latin-1')))
|
||||
data = b''.join(data)
|
||||
rec.contentData = data
|
||||
rec.contentLength = len(data)
|
||||
rec.write(sock)
|
||||
|
||||
_environPrefixes = ['SERVER_', 'HTTP_', 'REQUEST_', 'REMOTE_', 'PATH_',
|
||||
'CONTENT_', 'DOCUMENT_', 'SCRIPT_']
|
||||
_environCopies = ['SCRIPT_NAME', 'QUERY_STRING', 'AUTH_TYPE']
|
||||
_environRenames = []
|
||||
|
||||
def _defaultFilterEnviron(self, environ):
|
||||
result = {}
|
||||
for n in environ.keys():
|
||||
iv = False
|
||||
for p in self._environPrefixes:
|
||||
if n.startswith(p):
|
||||
result[n] = environ[n]
|
||||
iv = True
|
||||
if n in self._environCopies:
|
||||
result[n] = environ[n]
|
||||
iv = True
|
||||
if n in self._environRenames:
|
||||
result[self._environRenames[n]] = environ[n]
|
||||
iv = True
|
||||
if not iv:
|
||||
result[n] = environ[n]
|
||||
|
||||
return result
|
||||
|
||||
def _lightFilterEnviron(self, environ):
|
||||
result = {}
|
||||
for n in environ.keys():
|
||||
if n.upper() == n:
|
||||
result[n] = environ[n]
|
||||
return result
|
||||
@@ -1,208 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import struct
|
||||
import fcgi_client
|
||||
|
||||
FCGI_Header = '!BBHHBx'
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except:
|
||||
from StringIO import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def get_header_data(sock):
|
||||
'''
|
||||
@name 获取头部32KB数据
|
||||
@param sock socketobject(fastcgi套接字对象)
|
||||
@return bytes
|
||||
'''
|
||||
headers_data = b''
|
||||
total_len = 0
|
||||
header_len = 1024 * 128
|
||||
while True:
|
||||
fastcgi_header = sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
headers_data += fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
headers_data += sd
|
||||
tlen -= len(sd)
|
||||
|
||||
total_len += fast_pack[3]
|
||||
if fast_pack[4]:
|
||||
sock.recv(fast_pack[4])
|
||||
if total_len > header_len:
|
||||
break
|
||||
return headers_data
|
||||
|
||||
|
||||
def format_header_data(headers_data):
|
||||
'''
|
||||
@name 格式化响应头
|
||||
@param headers_data bytes(fastcgi头部32KB数据)
|
||||
@return status int(响应状态), headers dict(响应头), bdata bytes(格式化响应头后的多余数据)
|
||||
'''
|
||||
status = '200 OK'
|
||||
headers = {}
|
||||
pos = 0
|
||||
while True:
|
||||
eolpos = headers_data.find(b'\n', pos)
|
||||
if eolpos < 0:
|
||||
break
|
||||
line = headers_data[pos:eolpos - 1]
|
||||
pos = eolpos + 1
|
||||
line = line.strip()
|
||||
if len(line) < 2:
|
||||
break
|
||||
if line.find(b':') == -1:
|
||||
continue
|
||||
header, value = line.split(b':', 1)
|
||||
header = header.strip()
|
||||
value = value.strip()
|
||||
if isinstance(header, bytes):
|
||||
header = header.decode()
|
||||
value = value.decode()
|
||||
if header == 'Status':
|
||||
status = value
|
||||
if status.find(' ') < 0:
|
||||
status += ' BTPanel'
|
||||
else:
|
||||
headers[header] = value
|
||||
bdata = headers_data[pos:]
|
||||
status = int(status.split(' ')[0])
|
||||
return status, headers, bdata
|
||||
|
||||
|
||||
def resp_sock(sock, bdata):
|
||||
'''
|
||||
@name 以流的方式发送剩余数据
|
||||
@param sock socketobject(fastcgi套接字对象)
|
||||
@param bdata bytes(格式化响应头后的多余数据)
|
||||
@return yield bytes
|
||||
'''
|
||||
# 发送除响应头以外的多余头部数据
|
||||
yield bdata
|
||||
while True:
|
||||
fastcgi_header = sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
yield fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
tlen -= len(sd)
|
||||
if sd:
|
||||
yield sd
|
||||
|
||||
if fast_pack[4]:
|
||||
sock.recv(fast_pack[4])
|
||||
sock.close()
|
||||
|
||||
|
||||
class fpm(object):
|
||||
|
||||
def __init__(self, sock=None, document_root='', last_path=''):
|
||||
'''
|
||||
@name 实例化FPM对象
|
||||
@param sock string(unixsocket路径)
|
||||
@param document_root string(PHP文档根目录)
|
||||
@return FPM
|
||||
'''
|
||||
if sock:
|
||||
self.fcgi_sock = sock
|
||||
if document_root[-1:] != '/':
|
||||
document_root += '/'
|
||||
self.document_root = document_root
|
||||
self.last_path = last_path
|
||||
|
||||
def load_url_public(self, url, content=b'', method='GET', content_type='application/x-www-form-urlencoded'):
|
||||
'''
|
||||
@name 转发URL到PHP-FPM 公共
|
||||
@param url string(URI地址)
|
||||
@param content stream(POST数据io对象)
|
||||
@return fastcgi-socket
|
||||
'''
|
||||
fcgi = fcgi_client.FCGIApp(connect=self.fcgi_sock)
|
||||
try:
|
||||
script_name, query_string = url.split('?')
|
||||
except ValueError:
|
||||
script_name = url
|
||||
query_string = ''
|
||||
|
||||
content_length = len(content)
|
||||
if content:
|
||||
content = StringIO(content)
|
||||
|
||||
env = {
|
||||
'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name),
|
||||
'QUERY_STRING': query_string,
|
||||
'REQUEST_METHOD': method,
|
||||
'SCRIPT_NAME': self.last_path + script_name,
|
||||
'REQUEST_URI': url,
|
||||
'GATEWAY_INTERFACE': 'CGI/1.1',
|
||||
'SERVER_SOFTWARE': 'MW-Panel',
|
||||
'REDIRECT_STATUS': '200',
|
||||
'CONTENT_TYPE': content_type,
|
||||
'CONTENT_LENGTH': str(content_length),
|
||||
'DOCUMENT_URI': script_name,
|
||||
'DOCUMENT_ROOT': self.document_root,
|
||||
'SERVER_PROTOCOL': 'HTTP/1.1',
|
||||
'REMOTE_ADDR': '127.0.0.1',
|
||||
'REMOTE_PORT': '7200',
|
||||
'SERVER_ADDR': '127.0.0.1',
|
||||
'SERVER_PORT': '80',
|
||||
'SERVER_NAME': 'MW-Panel'
|
||||
}
|
||||
|
||||
fpm_sock = fcgi(env, content)
|
||||
|
||||
_data = b''
|
||||
while True:
|
||||
fastcgi_header = fpm_sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
_data += fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = fpm_sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
tlen -= len(sd)
|
||||
_data += sd
|
||||
if fast_pack[4]:
|
||||
fpm_sock.recv(fast_pack[4])
|
||||
status, headers, data = format_header_data(_data)
|
||||
return data
|
||||
@@ -1,43 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import smtplib
|
||||
|
||||
from email import encoders
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import parseaddr, formataddr
|
||||
|
||||
|
||||
def _format_addr(s):
|
||||
name, addr = parseaddr(s)
|
||||
return formataddr((Header(name, 'utf-8').encode(), addr))
|
||||
|
||||
|
||||
def send(smtp_host, smtp_port, username, password, to_mail, subject, content):
|
||||
|
||||
smtp = smtplib.SMTP()
|
||||
smtp.connect(smtp_host, port=smtp_port)
|
||||
smtp.login(user=username, password=password)
|
||||
|
||||
msg = MIMEText(content, 'plain', 'utf-8')
|
||||
msg['From'] = _format_addr(username)
|
||||
msg['To'] = _format_addr(to_mail)
|
||||
msg['Subject'] = Header(subject, 'utf-8').encode()
|
||||
|
||||
smtp.sendmail(from_addr=username, to_addrs=to_mail, msg=msg.as_string())
|
||||
return True
|
||||
|
||||
|
||||
def sendSSL(smtp_host, smtp_port, username, password, to_mail, subject, content):
|
||||
|
||||
smtp = smtplib.SMTP_SSL(smtp_host, port=smtp_port)
|
||||
smtp.login(user=username, password=password)
|
||||
|
||||
msg = MIMEText(content, 'plain', 'utf-8')
|
||||
msg['From'] = _format_addr(username)
|
||||
msg['To'] = _format_addr(to_mail)
|
||||
msg['Subject'] = Header(subject, 'utf-8').encode()
|
||||
|
||||
smtp.sendmail(from_addr=username, to_addrs=to_mail, msg=msg.as_string())
|
||||
smtp.quit()
|
||||
return True
|
||||
@@ -1,116 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pymysql.cursors
|
||||
|
||||
|
||||
class ORM:
|
||||
__DB_PASS = None
|
||||
__DB_USER = 'root'
|
||||
__DB_PORT = 3306
|
||||
__DB_NAME = ''
|
||||
__DB_HOST = 'localhost'
|
||||
__DB_CONN = None
|
||||
__DB_CUR = None
|
||||
__DB_ERR = None
|
||||
__DB_CNF = '/etc/my.cnf'
|
||||
__DB_SOCKET = '/www/server/mysql/mysql.sock'
|
||||
|
||||
__DB_CHARSET = "utf8"
|
||||
|
||||
def __Conn(self):
|
||||
'''连接数据库'''
|
||||
try:
|
||||
|
||||
if os.path.exists(self.__DB_SOCKET):
|
||||
try:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
|
||||
else:
|
||||
try:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
cursorclass=pymysql.cursors.DictCursor)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
cursorclass=pymysql.cursors.DictCursor)
|
||||
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
return True
|
||||
except Exception as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
def setDbConf(self, conf):
|
||||
self.__DB_CNF = conf
|
||||
|
||||
def setSocket(self, sock):
|
||||
self.__DB_SOCKET = sock
|
||||
|
||||
def setCharset(self, charset):
|
||||
self.__DB_CHARSET = charset
|
||||
|
||||
def setHost(self, host):
|
||||
self.__DB_HOST = host
|
||||
|
||||
def setPort(self, port):
|
||||
self.__DB_PORT = port
|
||||
|
||||
def setUser(self, user):
|
||||
self.__DB_USER = user
|
||||
|
||||
def setPwd(self, pwd):
|
||||
self.__DB_PASS = pwd
|
||||
|
||||
def getPwd(self):
|
||||
return self.__DB_PASS
|
||||
|
||||
def setDbName(self, name):
|
||||
self.__DB_NAME = name
|
||||
|
||||
def execute(self, sql):
|
||||
# 执行SQL语句返回受影响行
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
result = self.__DB_CUR.execute(sql)
|
||||
self.__DB_CONN.commit()
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def query(self, sql):
|
||||
# 执行SQL语句返回数据集
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
self.__DB_CUR.execute(sql)
|
||||
result = self.__DB_CUR.fetchall()
|
||||
# print(result)
|
||||
# 将元组转换成列表
|
||||
# data = map(list, result)
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def __Close(self):
|
||||
# 关闭连接
|
||||
self.__DB_CUR.close()
|
||||
self.__DB_CONN.close()
|
||||
@@ -1,115 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class ORM:
|
||||
__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'
|
||||
|
||||
__DB_SOCKET = '/www/server/mysql/mysql.sock'
|
||||
__DB_CHARSET = 'utf8'
|
||||
|
||||
def __Conn(self):
|
||||
'''连接MYSQL数据库'''
|
||||
try:
|
||||
|
||||
try:
|
||||
import MySQLdb
|
||||
except Exception as ex:
|
||||
self.__DB_ERR = ex
|
||||
return False
|
||||
|
||||
# print(self.__DB_HOST)
|
||||
# print(self.__DB_USER)
|
||||
# print(self.__DB_PASS)
|
||||
# print(self.__DB_PORT)
|
||||
# print(self.__DB_CHARSET)
|
||||
# print(self.__DB_SOCKET)
|
||||
if os.path.exists(self.__DB_SOCKET):
|
||||
try:
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
|
||||
except Exception as e:
|
||||
print(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=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
|
||||
else:
|
||||
try:
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
|
||||
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
|
||||
return True
|
||||
except MySQLdb.Error as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
def setDbConf(self, conf):
|
||||
self.__DB_CNF = conf
|
||||
|
||||
def setSocket(self, sock):
|
||||
self.__DB_SOCKET = sock
|
||||
|
||||
def setCharset(self, charset):
|
||||
self.__DB_CHARSET = charset
|
||||
|
||||
def setPort(self, port):
|
||||
self.__DB_PORT = port
|
||||
|
||||
def setPwd(self, pwd):
|
||||
self.__DB_PASS = pwd
|
||||
|
||||
def getPwd(self):
|
||||
return self.__DB_PASS
|
||||
|
||||
def setDbName(self, name):
|
||||
self.__DB_NAME = name
|
||||
|
||||
def setUser(self, user):
|
||||
self.__DB_USER = user
|
||||
|
||||
def execute(self, sql):
|
||||
# 执行SQL语句返回受影响行
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
result = self.__DB_CUR.execute(sql)
|
||||
self.__DB_CONN.commit()
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def query(self, sql):
|
||||
# 执行SQL语句返回数据集
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
self.__DB_CUR.execute(sql)
|
||||
result = self.__DB_CUR.fetchall()
|
||||
# 将元组转换成列表
|
||||
data = map(list, result)
|
||||
self.__Close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
# 关闭连接
|
||||
def __Close(self):
|
||||
self.__DB_CUR.close()
|
||||
self.__DB_CONN.close()
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/local/lib/python2.7/bin
|
||||
|
||||
|
||||
|
||||
find . -name .DS_Store | xargs rm -rf
|
||||
find . -type d -name "*.pyc" | xargs rm -rf
|
||||
@@ -1,99 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
MDIR=$(dirname "$DIR")
|
||||
|
||||
|
||||
PATH=$PATH:$DIR/bin
|
||||
if [ -f bin/activate ];then
|
||||
source bin/activate
|
||||
|
||||
if [ "$?" != "0" ];then
|
||||
echo "load local python env fail!"
|
||||
fi
|
||||
fi
|
||||
|
||||
export LC_ALL="en_US.UTF-8"
|
||||
|
||||
|
||||
mw_start_task()
|
||||
{
|
||||
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "starting mw-tasks... \c"
|
||||
cd $DIR && python3 task.py >> ${DIR}/logs/task.log 2>&1 &
|
||||
sleep 0.3
|
||||
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "\033[31mfailed\033[0m"
|
||||
echo '------------------------------------------------------'
|
||||
tail -n 20 $DIR/logs/task.log
|
||||
echo '------------------------------------------------------'
|
||||
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
|
||||
return;
|
||||
fi
|
||||
echo -e "\033[32mdone\033[0m"
|
||||
else
|
||||
echo "starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
|
||||
fi
|
||||
}
|
||||
|
||||
mw_start(){
|
||||
gunicorn -c setting.py app:app
|
||||
#安全启动
|
||||
mw_start_task
|
||||
}
|
||||
|
||||
|
||||
mw_start_debug(){
|
||||
if [ ! -f $DIR/logs/task.log ];then
|
||||
echo '' > $DIR/logs/task.log
|
||||
fi
|
||||
|
||||
python3 task.py >> $DIR/logs/task.log 2>&1 &
|
||||
port=7200
|
||||
if [ -f /www/server/mdserver-web/data/port.pl ];then
|
||||
port=$(cat /www/server/mdserver-web/data/port.pl)
|
||||
fi
|
||||
# gunicorn -b :${port} -k gevent -w 1 app:app
|
||||
gunicorn -b :${port} -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
|
||||
}
|
||||
|
||||
mw_start_debug2(){
|
||||
python3 task.py >> $DIR/logs/task.log 2>&1 &
|
||||
gunicorn -b :7200 -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
|
||||
}
|
||||
|
||||
|
||||
mw_stop()
|
||||
{
|
||||
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
|
||||
for i in $PLIST
|
||||
do
|
||||
kill -9 $i > /dev/null 2>&1
|
||||
done
|
||||
|
||||
pids=`ps -ef|grep task.py | grep -v grep |awk '{print $2}'`
|
||||
arr=($pids)
|
||||
for p in ${arr[@]}
|
||||
do
|
||||
kill -9 $p > /dev/null 2>&1
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start') mw_start;;
|
||||
'stop') mw_stop;;
|
||||
'restart')
|
||||
mw_stop
|
||||
mw_start
|
||||
;;
|
||||
'debug')
|
||||
mw_stop
|
||||
mw_start_debug
|
||||
;;
|
||||
'debug2')
|
||||
mw_stop
|
||||
mw_start_debug2
|
||||
;;
|
||||
esac
|
||||
@@ -1,79 +0,0 @@
|
||||
### 常用命令说明
|
||||
|
||||
|
||||
- 面板相关命令
|
||||
|
||||
```
|
||||
/etc/init.d/mw default | 显示登录信息
|
||||
/etc/init.d/mw db | 快捷连接数据库
|
||||
----------------------------------------
|
||||
mw open | 开启面板
|
||||
mw close | 关闭面板
|
||||
|
||||
mw debug | 开发测试
|
||||
mw venv | 进入虚拟环境
|
||||
mw mirror | 切换镜像
|
||||
mw install_app | 快捷安装常用软件
|
||||
mw update | 更新到正式
|
||||
mw update_dev | 更新到开发
|
||||
|
||||
service mw [start|stop|reload|restart|status]
|
||||
```
|
||||
|
||||
- OpenResty
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] openresty
|
||||
|
||||
```
|
||||
|
||||
- MySQL
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] mysql
|
||||
|
||||
```
|
||||
|
||||
- MariaDB
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] mariadb
|
||||
|
||||
```
|
||||
|
||||
- PHP
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] php[54-81]
|
||||
|
||||
systemctl start php71
|
||||
```
|
||||
|
||||
- Redis
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] redis
|
||||
|
||||
```
|
||||
|
||||
- Memcached
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] memcached
|
||||
|
||||
```
|
||||
|
||||
|
||||
- sphinx
|
||||
|
||||
```
|
||||
|
||||
systemctl [start|stop|reload|restart|status] sphinx
|
||||
|
||||
```
|
||||
@@ -1,71 +0,0 @@
|
||||
### 兼容性测试报告
|
||||
|
||||
快速测试命令
|
||||
|
||||
```
|
||||
cd /www/server/mdserver-web/scripts/quick && bash debug.sh
|
||||
cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
|
||||
```
|
||||
|
||||
|
||||
| 系统名称 | 面板 | OpenResty |
|
||||
| ----------------- |---------------|---------------|
|
||||
| CentOS 7.9 |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |
|
||||
| Debian 12.0 |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |
|
||||
|
||||
|
||||
|
||||
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |PHP82 |PHP83 |
|
||||
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
|
||||
|
||||
|
||||
| 系统名称 | MySQL55|MySQL56|MySQL57|MySQL80|
|
||||
| ----------------- |-------|--------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |
|
||||
| Debian 12 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
+1
-11
@@ -4,18 +4,13 @@
|
||||
"type":0,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"已安装",
|
||||
"type":-1,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"运行环境",
|
||||
"type":1,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"数据软件",
|
||||
"title":"缓存软件",
|
||||
"type":2,
|
||||
"ps":""
|
||||
},
|
||||
@@ -33,10 +28,5 @@
|
||||
"title":"其他插件",
|
||||
"type":5,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"辅助插件",
|
||||
"type":6,
|
||||
"ps":""
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
True
|
||||
+41
-45
@@ -19,6 +19,19 @@ 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,
|
||||
@@ -27,40 +40,52 @@ CREATE TABLE IF NOT EXISTS `crontab` (
|
||||
`where_hour` INTEGER,
|
||||
`where_minute` INTEGER,
|
||||
`echo` TEXT,
|
||||
`addtime` TEXT,
|
||||
`status` INTEGER DEFAULT '1',
|
||||
`save` INTEGER DEFAULT '3',
|
||||
`backup_to` TEXT DEFAULT 'off',
|
||||
`sname` TEXT,
|
||||
`sbody` TEXT,
|
||||
'stype' TEXT,
|
||||
`urladdress` 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
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `firewall` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`port` TEXT,
|
||||
`protocol` TEXT DEFAULT 'tcp',
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
ALTER TABLE `firewall` ADD COLUMN `protocol` TEXT DEFAULT 'tcp';
|
||||
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');
|
||||
|
||||
INSERT INTO `firewall` (`id`, `port`, `protocol`, `ps`, `addtime`) VALUES
|
||||
(1, '80', 'tcp','网站默认端口', '0000-00-00 00:00:00'),
|
||||
(2, '443', 'tcp/udp', 'HTTPS', '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,
|
||||
`type` TEXT,
|
||||
`log` TEXT,
|
||||
`uid` INTEGER DEFAULT '1',
|
||||
`addtime` TEXT
|
||||
);
|
||||
ALTER TABLE `logs` ADD COLUMN `uid` INTEGER DEFAULT '1';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -68,17 +93,10 @@ CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`path` TEXT,
|
||||
`status` TEXT,
|
||||
`index` TEXT,
|
||||
`type_id` INTEGER,
|
||||
`ps` TEXT,
|
||||
`edate` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `site_types` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `domain` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pid` INTEGER,
|
||||
@@ -98,7 +116,7 @@ CREATE TABLE IF NOT EXISTS `users` (
|
||||
);
|
||||
|
||||
INSERT INTO `users` (`id`, `username`, `password`, `login_ip`, `login_time`, `phone`, `email`) VALUES
|
||||
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2022-02-02 00:00:00', 0, 'midoks@163.com');
|
||||
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2016-12-10 15:12:56', 0, '287962566@qq.com');
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tasks` (
|
||||
@@ -111,25 +129,3 @@ CREATE TABLE IF NOT EXISTS `tasks` (
|
||||
`end` INTEGER,
|
||||
`execstr` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `temp_login` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`token` REAL,
|
||||
`salt` REAL,
|
||||
`state` INTEGER,
|
||||
`login_time` INTEGER,
|
||||
`login_addr` REAL,
|
||||
`logout_time` INTEGER,
|
||||
`expire` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `panel` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`title` TEXT,
|
||||
`url` TEXT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`click` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
server
|
||||
{
|
||||
# reuseport 只能在一个server出现一次
|
||||
listen {$PORT};
|
||||
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
|
||||
|
||||
#301-START
|
||||
|
||||
#PROXY-START
|
||||
|
||||
#ERROR-PAGE-START
|
||||
#error_page 404 /404.html;
|
||||
#error_page 502 /502.html;
|
||||
#ERROR-PAGE-END
|
||||
|
||||
#PHP-INFO-START
|
||||
include {$PHP_DIR}/conf/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|js|css)$
|
||||
{
|
||||
expires 30d;
|
||||
error_log /dev/null;
|
||||
access_log /dev/null;
|
||||
}
|
||||
|
||||
access_log {$LOGPATH}/{$SERVER_NAME}.log main;
|
||||
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
|
||||
#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 {$PHP_DIR}/conf/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|js|css)$
|
||||
{
|
||||
error_log /dev/null;
|
||||
access_log /dev/null;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
access_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.log;
|
||||
error_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.error.log;
|
||||
}
|
||||
#BINDING-{$DIRBIND}-END
|
||||
@@ -1,23 +0,0 @@
|
||||
server
|
||||
{
|
||||
listen {$PORT};
|
||||
listen [::]:{$PORT};
|
||||
|
||||
server_name {$SERVER_NAME};
|
||||
index index.php index.html index.htm default.php default.htm default.html;
|
||||
|
||||
#SSL-START
|
||||
#error_page 404/404.html;
|
||||
#SSL-END
|
||||
|
||||
#PROXY-START
|
||||
location ^~ / {
|
||||
proxy_pass http://0.0.0.0:{$PANAL_PORT}/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
}
|
||||
#PROXY-END
|
||||
|
||||
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
存放VIP关键数据
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -rf ./*.pyc
|
||||
rm -rf ./*/*.pyc
|
||||
|
||||
#open "http://127.0.0.1:7200"
|
||||
@@ -1,62 +0,0 @@
|
||||
FROM debian:10.12-slim
|
||||
|
||||
STOPSIGNAL SIGRTMIN+3
|
||||
|
||||
RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
|
||||
/etc/systemd/system/*.wants/* \
|
||||
/lib/systemd/system/local-fs.target.wants/* \
|
||||
/lib/systemd/system/sockets.target.wants/*udev* \
|
||||
/lib/systemd/system/sockets.target.wants/*initctl* \
|
||||
/lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \
|
||||
/lib/systemd/system/systemd-update-utmp*
|
||||
|
||||
RUN apt update -y && \
|
||||
apt install -y devscripts && \
|
||||
apt install -y wget zip unzip && \
|
||||
apt-get install -y locales && \
|
||||
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \
|
||||
locale-gen en_US.UTF-8 && \
|
||||
export LC_ALL=en_US.UTF-8 && \
|
||||
export LANG=en_US.UTF-8 && \
|
||||
export LANGUAGE=en_US.UTF-8 && \
|
||||
localedef -i en_US -f UTF-8 en_US.UTF-8 && \
|
||||
mkdir -p /www/server && \
|
||||
mkdir -p /www/wwwroot && \
|
||||
mkdir -p /www/wwwlogs && \
|
||||
mkdir -p /www/backup/database && \
|
||||
mkdir -p /www/backup/site && \
|
||||
wget -O /tmp/dev.zip https://github.com/midoks/mdserver-web/archive/refs/heads/dev.zip && \
|
||||
cd /tmp && unzip /tmp/dev.zip && \
|
||||
mv -f /tmp/mdserver-web-dev /www/server/mdserver-web && \
|
||||
rm -rf /tmp/dev.zip && \
|
||||
rm -rf /tmp/mdserver-web-dev && \
|
||||
cd /www/server/mdserver-web && \
|
||||
bash scripts/install/debian.sh && \
|
||||
cd /www/server/mdserver-web/ && \
|
||||
/www/server/mdserver-web/bin/python tools.py username username && \
|
||||
cd /www/server/mdserver-web/ && \
|
||||
/www/server/mdserver-web/bin/python tools.py panel password
|
||||
|
||||
RUN cd /www/server/mdserver-web/plugins/php && \
|
||||
bash install.sh install 74 && \
|
||||
cd /www/server/mdserver-web/plugins/openresty && \
|
||||
bash install.sh install 1.21.4.1 && \
|
||||
cd /www/server/mdserver-web/plugins/mysql && \
|
||||
bash install.sh install 5.6 && \
|
||||
cd /www/server/mdserver-web/plugins/phpmyadmin && \
|
||||
bash install.sh install 4.4.15 && \
|
||||
systemctl enable openresty && \
|
||||
systemctl enable php74 && \
|
||||
systemctl enable mysql
|
||||
|
||||
RUN rm -rf /www/server/mysql/data
|
||||
|
||||
ADD ./start.sh /start.sh
|
||||
ADD start.service /usr/lib/systemd/system/start.service
|
||||
#RUN systemctl enable start
|
||||
|
||||
CMD [ "/lib/systemd/systemd", "log-level=info", "unit=sysinit.target" ]
|
||||
|
||||
EXPOSE 7200 80 443 888
|
||||
|
||||
VOLUME [ "/www" ]
|
||||
@@ -1,9 +0,0 @@
|
||||
[Unit]
|
||||
Description=Customize the script
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/start.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1 +0,0 @@
|
||||
#!/bin/bash
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
# coding: utf-8
|
||||
|
||||
# 使用示例:
|
||||
# 1、将此文件重命名为btkill.py , 然后上传到服务器/root目录
|
||||
# 2、执行 python /root/btkill.py
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
sys.path.append("/usr/local/lib/python2.7/site-packages")
|
||||
import psutil
|
||||
|
||||
|
||||
class btkill:
|
||||
__limit = 10 # Cpu使用率触发上限
|
||||
__vmsize = 1048576 / 4 # 虚拟内存触发上限(字节)
|
||||
|
||||
def checkMain(self):
|
||||
pids = psutil.pids()
|
||||
print pids
|
||||
num = 0
|
||||
for pid in pids:
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
if p.exe() == "":
|
||||
continue
|
||||
name = p.name()
|
||||
if self.whiteList(name):
|
||||
continue
|
||||
cputimes = p.cpu_times()
|
||||
if cputimes.user < 0.1:
|
||||
continue
|
||||
print p
|
||||
percent = p.cpu_percent(interval=0.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()
|
||||
num += 1
|
||||
print log + " >> killed\n"
|
||||
except Exception as ex:
|
||||
print str(ex)
|
||||
return num
|
||||
|
||||
# 检查白名单
|
||||
def whiteList(self, name):
|
||||
wlist = ['yum', 'apt-get', 'apt', 'redis-cli', 'memcached', 'sshd', 'vm', 'vim', 'htop', 'top', 'sh', 'bash', 'zip', 'gzip', 'rsync',
|
||||
'tar', 'unzip', 'php', 'composer', 'pkill', 'mongo', 'mongod', 'php-fpm', 'nginx', 'httpd', 'lsof', 'ps', 'redis-server',
|
||||
'mysqld', 'mysqld_safe', 'mysql', 'pure-ftpd', 'sparse_dd', 'stunnel', 'squeezed', 'vncterm', 'awk', 'ruby', 'postgres',
|
||||
'mpathalert', 'vncterm', 'multipathd', 'fe', 'elasticsyslog', 'syslogd', 'v6d', 'xapi', 'screen', 'runsvdir', 'svlogd',
|
||||
'java', 'udevd', 'ntpd', 'irqbalance', 'qmgr', 'wpa_supplicant', 'mysqld_safe', 'sftp-server', 'lvmetad', 'gitlab-web',
|
||||
'pure-ftpd', 'auditd', 'master', 'dbus-daemon', 'tapdisk', 'sshd', 'init', 'ksoftirqd', 'kworker', 'kmpathd',
|
||||
'kmpath_handlerd', 'python', 'kdmflush', 'bioset', 'crond', 'kthreadd', 'migration', 'rcu_sched', 'kjournald',
|
||||
'gcc', 'gcc++', 'nginx', 'mysqld', 'php-cgi', 'login', 'firewalld', 'iptables', 'systemd', 'network', 'dhclient',
|
||||
'systemd-journald', 'NetworkManager', 'systemd-logind', 'systemd-udevd', 'polkitd', 'tuned', 'rsyslogd', 'AliYunDunUpdate', 'AliYunDun', 'sendmail']
|
||||
wslist = ['vif', 'qemu', 'scsi_eh', 'xcp',
|
||||
'xen', 'docker', 'yunsuo', 'aliyun', 'PM2']
|
||||
|
||||
for key in wlist:
|
||||
if key == name:
|
||||
return True
|
||||
|
||||
for key in wslist:
|
||||
if name.find(key) != -1:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# 开始处理
|
||||
def start(self):
|
||||
num = 0
|
||||
while True:
|
||||
num += self.checkMain()
|
||||
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
|
||||
time.sleep(3)
|
||||
print '======================================='
|
||||
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print "正在检测异常进程..."
|
||||
print '======================================='
|
||||
c = btkill()
|
||||
c.start()
|
||||
@@ -1,420 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
'''
|
||||
doc: https://docs.python.org/zh-cn/3/library/ftplib.html
|
||||
'''
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
import paramiko
|
||||
import ftplib
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
DEBUG = True
|
||||
BLOCK_SIZE = 1024 * 1024 * 2
|
||||
# BLOCK_SIZE = 50
|
||||
PROGRESS_FILE_NAME = "PROGRESS_FILE_NAME"
|
||||
|
||||
"""
|
||||
=============自定义异常===================
|
||||
"""
|
||||
|
||||
|
||||
class OsError(Exception):
|
||||
"""OS端异常"""
|
||||
|
||||
|
||||
class ObjectNotFound(OsError):
|
||||
"""对象不存在时抛出的异常"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
message = "文件对象不存在。"
|
||||
super(ObjectNotFound, self).__init__(message, *args, **kwargs)
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
"""API参数错误异常"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
_api_error_msg = 'API资料校验失败,请核实!'
|
||||
super(APIError, self).__init__(_api_error_msg, *args, **kwargs)
|
||||
|
||||
|
||||
class FtpPSClient:
|
||||
_title = "FTP"
|
||||
_name = "ftp"
|
||||
__host = None
|
||||
__port = None
|
||||
__user = None
|
||||
__password = None
|
||||
default_port = 21
|
||||
default_backup_path = "/backup/"
|
||||
config_file = "cfg.json"
|
||||
|
||||
def __init__(self, load_config=True, timeout=10):
|
||||
self.timeout = timeout
|
||||
if load_config:
|
||||
data = self.get_config()
|
||||
self.injection_config(data)
|
||||
|
||||
def get_config(self):
|
||||
default_config = {
|
||||
"ftp_host": '',
|
||||
"ftp_user": '',
|
||||
"ftp_pass": '',
|
||||
"backup_path": self.default_backup_path
|
||||
}
|
||||
|
||||
cfg = mw.getServerDir() + "/backup_ftp/" + self.config_file
|
||||
if os.path.exists(cfg):
|
||||
data = mw.readFile(cfg)
|
||||
return json.loads(data)
|
||||
else:
|
||||
return default_config
|
||||
|
||||
def injection_config(self, data):
|
||||
self.__host = host = data["ftp_host"].strip()
|
||||
if host.find(':') == -1:
|
||||
self.__port = self.default_port
|
||||
else:
|
||||
self.__host = host.split(':')[0]
|
||||
self.__port = host.split(':')[1]
|
||||
|
||||
self.__user = data['ftp_user'].strip()
|
||||
self.__password = data['ftp_pass'].strip()
|
||||
bp = data['backup_path'].strip()
|
||||
if bp:
|
||||
self.backup_path = self.getPath(bp)
|
||||
else:
|
||||
self.backup_path = self.getPath(self.default_backup_path)
|
||||
|
||||
def authorize(self):
|
||||
try:
|
||||
if self.timeout is not None:
|
||||
ftp = ftplib.FTP(timeout=self.timeout)
|
||||
else:
|
||||
ftp = ftplib.FTP()
|
||||
|
||||
debuglevel = 0
|
||||
# if DEBUG:
|
||||
# debuglevel = 3
|
||||
ftp.set_debuglevel(debuglevel)
|
||||
# ftp.set_pasv(True)
|
||||
ftp.connect(self.__host, int(self.__port))
|
||||
ftp.login(self.__user, self.__password)
|
||||
return ftp
|
||||
except Exception as e:
|
||||
raise OsError("无法连接FTP客户端,请检查配置参数是否正确!")
|
||||
|
||||
# 取目录路径
|
||||
def getPath(self, path):
|
||||
if path[-1:] != '/':
|
||||
path += '/'
|
||||
if path[:1] != '/':
|
||||
path = '/' + path
|
||||
return path.replace('//', '/')
|
||||
|
||||
def generateDownloadUrl(self, object_name):
|
||||
|
||||
return 'ftp://' + \
|
||||
self.__user + ':' + \
|
||||
self.__password + '@' + \
|
||||
self.__host + ':' + \
|
||||
"/" + object_name
|
||||
|
||||
def buildDirName(self, data_type, file_name):
|
||||
import re
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+\."
|
||||
sub_search = re.search(file_regx, file_name)
|
||||
sub_path_name = ""
|
||||
if sub_search:
|
||||
sub_path_name = sub_search.groups()[0]
|
||||
sub_path_name += '/'
|
||||
|
||||
# 构建OS存储路径
|
||||
object_name = self.backup_path + \
|
||||
data_type + '/' + \
|
||||
sub_path_name + \
|
||||
file_name
|
||||
return object_name
|
||||
|
||||
def uploadFile(self, filename, data_type=None, *args, **kwargs):
|
||||
|
||||
client = self.authorize()
|
||||
|
||||
local_file_name = filename
|
||||
filename = os.path.abspath(filename)
|
||||
dirname = os.path.dirname(filename)
|
||||
temp_name = os.path.split(filename)[1]
|
||||
|
||||
object_name = self.buildDirName(data_type, temp_name)
|
||||
|
||||
upload_tmp_dir = os.path.join(dirname, ".upload_tmp")
|
||||
if not os.path.exists(upload_tmp_dir):
|
||||
os.mkdir(upload_tmp_dir)
|
||||
|
||||
print("|-正在上传文件到 {}".format(object_name))
|
||||
|
||||
total_bytes = os.path.getsize(filename)
|
||||
object_md5_name = mw.md5(object_name)
|
||||
pg_file = os.path.join(upload_tmp_dir, object_md5_name + ".pl")
|
||||
|
||||
block_size = BLOCK_SIZE
|
||||
if kwargs.get("block_size"):
|
||||
try:
|
||||
block_size = float(kwargs.get("block_size"))
|
||||
except:
|
||||
pass
|
||||
|
||||
remote_file_size = None
|
||||
if not os.path.exists(pg_file):
|
||||
# import uuid
|
||||
# uid = str(uuid.uuid1())
|
||||
progress_info = {
|
||||
"filename": local_file_name,
|
||||
"total_bytes": total_bytes,
|
||||
"uploaded_bytes": 0,
|
||||
}
|
||||
mw.writeFile(pg_file, json.dumps(progress_info))
|
||||
else:
|
||||
progress_info = json.loads(mw.readFile(pg_file))
|
||||
if total_bytes == progress_info.get("total_bytes"):
|
||||
# 取远程文件大小
|
||||
_max_loop = 10
|
||||
while _max_loop > 0:
|
||||
try:
|
||||
time.sleep(1)
|
||||
remote_file_size = client.size(object_name)
|
||||
if remote_file_size > total_bytes:
|
||||
remote_file_size = None
|
||||
break
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(type(e))
|
||||
print(e)
|
||||
_max_loop -= 1
|
||||
else:
|
||||
remote_file_size = None
|
||||
|
||||
uploaded_bytes = 0 if remote_file_size is None else remote_file_size
|
||||
|
||||
dir_name = os.path.split(object_name)[0]
|
||||
if dir_name:
|
||||
self.createDirP(dir_name)
|
||||
|
||||
upload_start = time.time()
|
||||
|
||||
try:
|
||||
if total_bytes > 1024 * 1024 * 1024:
|
||||
with open(local_file_name, 'rb') as file_handler:
|
||||
if remote_file_size is not None:
|
||||
file_handler.seek(remote_file_size)
|
||||
|
||||
client.voidcmd("TYPE I")
|
||||
datasock = ''
|
||||
esize = ''
|
||||
|
||||
datasock, esize = client.ntransfercmd(
|
||||
"STOR " + object_name, remote_file_size)
|
||||
|
||||
while True:
|
||||
buf = file_handler.read(block_size)
|
||||
if not len(buf):
|
||||
break
|
||||
datasock.sendall(buf)
|
||||
uploaded_bytes += len(buf)
|
||||
if DEBUG:
|
||||
print('\ruploading %.2f%%' %
|
||||
(float(uploaded_bytes) / total_bytes * 100))
|
||||
|
||||
print("uploaded_bytes", uploaded_bytes)
|
||||
if uploaded_bytes == total_bytes:
|
||||
break
|
||||
datasock.close()
|
||||
|
||||
if DEBUG:
|
||||
print('close data handle')
|
||||
try:
|
||||
client.voidcmd('NOOP')
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print("Send NOOP command error:")
|
||||
print(e)
|
||||
else:
|
||||
if DEBUG:
|
||||
print('keep alive cmd success')
|
||||
client.voidresp()
|
||||
if DEBUG:
|
||||
print('No loop cmd')
|
||||
else:
|
||||
# 小于1G文件直接上传
|
||||
file_handler = open(local_file_name, "rb")
|
||||
client.storbinary('STOR %s' % object_name,
|
||||
file_handler, blocksize=block_size)
|
||||
file_handler.close()
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
completed_file_size = None
|
||||
_max_loop = 10
|
||||
while _max_loop > 0:
|
||||
try:
|
||||
time.sleep(1)
|
||||
completed_file_size = client.size(object_name)
|
||||
break
|
||||
except Exception as e:
|
||||
_max_loop -= 1
|
||||
if DEBUG:
|
||||
print("size error:" + str(e))
|
||||
|
||||
# 上传完成
|
||||
if completed_file_size == total_bytes:
|
||||
if DEBUG:
|
||||
upload_completed = time.time()
|
||||
upload_diff = upload_completed - upload_start
|
||||
print("文件上传成功, 耗时: {}s。".format(upload_diff))
|
||||
if os.path.exists(pg_file):
|
||||
os.remove(pg_file)
|
||||
return True
|
||||
else:
|
||||
if os.path.exists(pg_file):
|
||||
os.remove(pg_file)
|
||||
print("文件上传后大小不一致!")
|
||||
|
||||
print("completed_file_size:" + str(completed_file_size))
|
||||
print("total_bytes:", total_bytes)
|
||||
print("object_md5_name:", object_md5_name)
|
||||
print("pg_file:", pg_file)
|
||||
print("filename:", filename)
|
||||
print("dirname:", dirname)
|
||||
print("object_name:", object_name)
|
||||
return False
|
||||
|
||||
def createDirP(self, dir_name):
|
||||
"""创建远程目录
|
||||
|
||||
:param dir_name: 目录名称
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
dirnames = dir_name.split('/')
|
||||
ftp = self.authorize()
|
||||
# ftp.cwd(get.path);
|
||||
for dirname in dirnames:
|
||||
if not dirname or not dirname.strip():
|
||||
continue
|
||||
try:
|
||||
flist = ftp.nlst()
|
||||
if not dirname in flist:
|
||||
ftp.mkd(dirname)
|
||||
except:
|
||||
# print("mlsd mode.")
|
||||
try:
|
||||
flist = list(ftp.mlsd())[1:]
|
||||
for f in flist:
|
||||
if dirname == f[0]:
|
||||
break
|
||||
else:
|
||||
ftp.mkd(dirname)
|
||||
except:
|
||||
return False
|
||||
ftp.cwd(dirname)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def createDir(self, path, name):
|
||||
ftp = self.authorize()
|
||||
path = self.getPath(path)
|
||||
ftp.cwd(path)
|
||||
try:
|
||||
ftp.mkd(name)
|
||||
ftp.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
ftp.close()
|
||||
return False
|
||||
|
||||
def deleteDir(self, path, dir_name):
|
||||
try:
|
||||
ftp = self.authorize()
|
||||
ftp.rmd(dir_name)
|
||||
return True
|
||||
except ftplib.error_perm as e:
|
||||
print("deleteDir:" + str(e) + ":" + dir_name)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def deleteFile(self, filename):
|
||||
try:
|
||||
ftp = self.authorize()
|
||||
ftp.delete(filename)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
def getList(self, path="/"):
|
||||
ftp = self.authorize()
|
||||
path = self.getPath(path)
|
||||
ftp.cwd(path)
|
||||
mlsd = False
|
||||
try:
|
||||
files = list(ftp.mlsd())
|
||||
mlsd = True
|
||||
except:
|
||||
try:
|
||||
files = ftp.nlst(path)
|
||||
mlsd = False
|
||||
except:
|
||||
raise RuntimeError("FTP服务器数据返回异常!")
|
||||
ftp.close()
|
||||
# print(files)
|
||||
f_list = []
|
||||
dirs = []
|
||||
data = []
|
||||
default_time = '1971/01/01 01:01:01'
|
||||
for dt in files:
|
||||
# print(dt)
|
||||
if mlsd:
|
||||
dt_name = dt[0]
|
||||
dt_info = dt[1]
|
||||
else:
|
||||
if dt.find("/") >= 0:
|
||||
dt = dt.split("/")[-1]
|
||||
tmp = {}
|
||||
tmp['name'] = dt_name
|
||||
if dt_name == '.' or dt_name == '..':
|
||||
continue
|
||||
|
||||
tmp['time'] = dt_info['modify']
|
||||
try:
|
||||
tmp['size'] = dt_info['size']
|
||||
tmp['type'] = "File"
|
||||
tmp['download'] = self.generateDownloadUrl(path + dt_name)
|
||||
f_list.append(tmp)
|
||||
except:
|
||||
tmp['size'] = dt_info['sizd']
|
||||
tmp['type'] = None
|
||||
tmp['download'] = ''
|
||||
dirs.append(tmp)
|
||||
data = dirs + f_list
|
||||
|
||||
mlist = {}
|
||||
mlist['path'] = path
|
||||
mlist['list'] = data
|
||||
return mlist
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,101 +0,0 @@
|
||||
<style>
|
||||
.upyunCon {
|
||||
height: 428px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 516px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 10px;
|
||||
font-style: oblique;
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
<div class="upyunCon">
|
||||
<div class="up-place pd15">
|
||||
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
|
||||
<input id="myPath" style="display:none;" type="text" value="">
|
||||
<div class="place-input pull-left">
|
||||
<div style="width:1400px;height:28px"><ul></ul></div>
|
||||
</div>
|
||||
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
|
||||
<button class="btn btn-default btn-sm pull-right btn-title" onclick="upyunApi()">帐户设置</button>
|
||||
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
|
||||
</div>
|
||||
|
||||
<div class="upyunlist pd15">
|
||||
<div class="divtable" style="margin-bottom:15px">
|
||||
<table class="table table-hover">
|
||||
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
|
||||
<tbody class="list-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=backup_ftp&f=js/backup_ftp.js", function(){
|
||||
osList('/');
|
||||
});
|
||||
</script>
|
||||
@@ -1,310 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
# print(sys.platform)
|
||||
if sys.platform != "darwin":
|
||||
os.chdir("/www/server/mdserver-web")
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
import db
|
||||
|
||||
_ver = sys.version_info
|
||||
is_py2 = (_ver[0] == 2)
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
DEBUG = False
|
||||
|
||||
if is_py2:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'backup_ftp'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from ftp_client import FtpPSClient
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
|
||||
def getConf():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置", [])
|
||||
data = mw.readFile(cfg)
|
||||
data = json.loads(data)
|
||||
return mw.returnJson(True, "OK", data)
|
||||
|
||||
|
||||
def setConf():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['use_sftp', 'ftp_user',
|
||||
'ftp_pass', 'ftp_host', 'backup_path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
|
||||
values = ['ftp_user',
|
||||
'ftp_pass',
|
||||
'ftp_host']
|
||||
for v in values:
|
||||
if args[v] == '':
|
||||
return mw.returnJson(False, '必填资料不能为空,请核实!', [])
|
||||
|
||||
if args['backup_path'] == '':
|
||||
args['backup_path'] = "/backup"
|
||||
|
||||
try:
|
||||
ftp = FtpPSClient(load_config=False)
|
||||
ftp.injection_config(args)
|
||||
data = ftp.getList("/")
|
||||
if data:
|
||||
mw.writeFile(cfg, mw.getJson(args))
|
||||
return mw.returnJson(True, '设置成功', [])
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, "FTP校验失败,请核实!\n" + str(e), [])
|
||||
|
||||
|
||||
def getList():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
try:
|
||||
ftp = FtpPSClient()
|
||||
flist = ftp.getList(args['path'])
|
||||
return mw.returnJson(True, "ok", flist)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, str(e), [])
|
||||
|
||||
|
||||
def createDir():
|
||||
cfg = getServerDir() + "/cfg.json"
|
||||
if not os.path.exists(cfg):
|
||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.createDir(args['path'], args['name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "创建成功")
|
||||
return mw.returnJson(False, "创建失败")
|
||||
|
||||
|
||||
def deleteDir():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['dir_name', 'path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.deleteDir(args['path'], args['dir_name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def deleteFile():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'filename'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
ftp = FtpPSClient()
|
||||
isok = ftp.deleteFile(args['path'] + "/" + args['filename'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def backupAllFunc(stype):
|
||||
os.chdir(mw.getRunDir())
|
||||
|
||||
name = sys.argv[2]
|
||||
num = sys.argv[3]
|
||||
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
backups = []
|
||||
sql = db.Sql()
|
||||
|
||||
# print("stype:", stype)
|
||||
# 提前获取-清理多余备份
|
||||
if stype == 'site':
|
||||
pid = sql.table('sites').where('name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('0', pid)).field('id,filename').select()
|
||||
if stype == 'database':
|
||||
db_path = mw.getServerDir() + '/mysql'
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
if stype == 'path':
|
||||
backup_path = backup_dir + '/path'
|
||||
_name = 'path_{}'.format(os.path.basename(name))
|
||||
backups = findPathName(backup_path, _name)
|
||||
|
||||
# 其他类型关系性数据库(mysql类的)
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
db_path = mw.getServerDir() + '/' + plugin_name
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
|
||||
args = stype + " " + name + " " + num
|
||||
cmd = 'python3 ' + mw.getRunDir() + '/scripts/backup.py ' + args
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
args = "database " + name + " " + num
|
||||
cmd = 'python3 ' + mw.getRunDir() + '/plugins/' + plugin_name + \
|
||||
'/scripts/backup.py ' + args
|
||||
|
||||
os.system(cmd)
|
||||
|
||||
# 开始执行上传信息.
|
||||
|
||||
if stype.find('database_') > -1:
|
||||
bk_name = 'database'
|
||||
plugin_name = stype.replace('database_', '')
|
||||
bk_prefix = plugin_name + '/db'
|
||||
stype = 'database'
|
||||
else:
|
||||
bk_prefix = prefix_dict[stype]
|
||||
bk_name = stype
|
||||
|
||||
find_path = mw.getBackupDir() + '/' + bk_name + '/' + bk_prefix + '_' + name
|
||||
find_new_file = "ls " + find_path + \
|
||||
"_* | grep '.gz' | cut -d \ -f 1 | awk 'END {print}'"
|
||||
|
||||
filename = mw.execShell(find_new_file)[0].strip()
|
||||
if filename == "":
|
||||
mw.echoInfo("not find upload file!")
|
||||
return ''
|
||||
|
||||
print("|-准备上传文件 {}".format(filename))
|
||||
ftp = FtpPSClient()
|
||||
ftp.uploadFile(filename, stype)
|
||||
|
||||
# print(backups)
|
||||
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
|
||||
mw.echoStart('开始删除远程备份')
|
||||
num = int(num)
|
||||
sep = len(backups) - num
|
||||
if sep > -1:
|
||||
for backup in backups:
|
||||
fn = os.path.basename(backup['filename'])
|
||||
object_name = ftp.buildDirName(stype, fn)
|
||||
ftp.deleteFile(object_name)
|
||||
mw.echoInfo("---已清理远程过期备份文件:" + object_name)
|
||||
sep -= 1
|
||||
if sep < 0:
|
||||
break
|
||||
mw.echoEnd('结束删除远程备份')
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def in_array(name, arr=[]):
|
||||
for x in arr:
|
||||
if name == x:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def installPreInspection():
|
||||
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 == 'install_pre_inspection':
|
||||
print(installPreInspection())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'set_config':
|
||||
print(setConf())
|
||||
elif func == "get_list":
|
||||
print(getList())
|
||||
elif func == "create_dir":
|
||||
print(createDir())
|
||||
elif func == "delete_dir":
|
||||
print(deleteDir())
|
||||
elif func == 'delete_file':
|
||||
print(deleteFile())
|
||||
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
|
||||
print(backupAllFunc(func))
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"title":"FTP存储空间",
|
||||
"hook":["backup"],
|
||||
"tip":"soft",
|
||||
"name":"backup_ftp",
|
||||
"type":"运行环境",
|
||||
"ps":"将网站或数据库打包备份到FTP存储空间",
|
||||
"versions":["1.0"],
|
||||
"install_pre_inspection":false,
|
||||
"shell":"install.sh",
|
||||
"checks":"server/backup_ftp",
|
||||
"path": "server/backup_ftp",
|
||||
"author":"midoks",
|
||||
"home":"https://github.com/midoks/mdserver-web",
|
||||
"date":"2022-10-23",
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
|
||||
|
||||
function bkfPost(method,args,callback){
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'backup_ftp', 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 getFtpLocalTime(data){
|
||||
var str = data.slice(0,4)+"/"+data.slice(4,6)+"/"+data.slice(6,8)
|
||||
+ " " + data.slice(8,10)+":"+data.slice(10,12)+":"+data.slice(12,14);
|
||||
return str;
|
||||
}
|
||||
|
||||
// 自定义部分
|
||||
var i = null;
|
||||
//设置API
|
||||
function upyunApi(){
|
||||
|
||||
bkfPost('conf', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var token = rdata.data;
|
||||
var check_status = token.use_sftp;
|
||||
var sftp_checked = check_status === "true" ? " checked=\"checked\"" : "";
|
||||
|
||||
if (typeof(token.ftp_host) == 'undefined'){
|
||||
token.ftp_host = '';
|
||||
}
|
||||
|
||||
if (typeof(token.ftp_user) == 'undefined'){
|
||||
token.ftp_user = '';
|
||||
}
|
||||
|
||||
if (typeof(token.ftp_pass) == 'undefined'){
|
||||
token.ftp_pass = '';
|
||||
}
|
||||
|
||||
if (typeof(token.backup_path) == 'undefined'){
|
||||
token.backup_path = '';
|
||||
}
|
||||
|
||||
var apicon = '<div class="bingfa mtb15" style="padding-bottom:0px;">\
|
||||
<p>\
|
||||
<span class="span_tit">使用SFTP:</span>\ <input style="width: 20px; vertical-align:middle;" type="checkbox" name="use_sftp"'+sftp_checked+'> 是否使用SFTP进行数据传输 \
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">Host:</span>\
|
||||
<input placeholder="请输入主机地址" style="width: 200px;" type="text" name="upyun_service" value="'+token.ftp_host+'"> *服务器地址,FTP默认端口21, SFTP默认端口22\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">用户名:</span>\
|
||||
<input style="width: 200px;" type="text" name="ftp_username" value="'+token.ftp_user+'"> *指定用户名\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">密码:</span>\
|
||||
<input style="width: 200px;" type="password" name="ftp_password" value="'+token.ftp_pass+'"> *登录密码\
|
||||
</p>\
|
||||
<p>\
|
||||
<span class="span_tit">存储位置:</span>\
|
||||
<input placeholder="请输入存储位置" style="width: 200px;" type="text" name="backup_path" value="'+token.backup_path+'"> *相对于根目录的路径,默认是/backup\
|
||||
</p>\
|
||||
</div>';
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "600px",
|
||||
title: "FTP/SFTP帐户设置",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:apicon,
|
||||
yes:function(index,layero){
|
||||
var data = {
|
||||
use_sftp:$("input[name='use_sftp']").prop('checked'),
|
||||
ftp_user:$("input[name='ftp_username']").val(),
|
||||
ftp_pass:$("input[name='ftp_password']").val(),
|
||||
ftp_host:$("input[name='upyun_service']").val(),
|
||||
backup_path:$("input[name='backup_path']").val()
|
||||
}
|
||||
bkfPost('set_config', data, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
if (rdata.status){
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(index);
|
||||
osList("/");
|
||||
},{icon:1},2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createDir(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "400px",
|
||||
title: "创建目录",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
|
||||
<p>\
|
||||
<span class="span_tit">目录名称:</span>\
|
||||
<input style="width: 200px;" type="text" name="newPath" value="">\
|
||||
</p>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("input[name='newPath']").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(index,layero){
|
||||
var name = $("input[name='newPath']").val();
|
||||
if(name == ''){
|
||||
layer.msg('目录名称不能为空!',{icon:2});
|
||||
return;
|
||||
}
|
||||
var path = $("#myPath").val();
|
||||
var dirname = name;
|
||||
// var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
bkfPost('create_dir', {path:path,name:dirname}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(rdata.status) {
|
||||
showMsg(rdata.msg, function(){
|
||||
layer.close(index);
|
||||
osList(path);
|
||||
} ,{icon:1}, 2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//删除文件
|
||||
function deleteFile(name, is_dir){
|
||||
if (is_dir === false){
|
||||
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
var filename = name;
|
||||
bkfPost('delete_file', {filename:filename,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
osList(path);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
safeMessage('删除文件夹','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
bkfPost('delete_dir', {dir_name:name,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
osList(path);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function osList(path){
|
||||
bkfPost('get_list', {path:path}, function(rdata){
|
||||
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
if(rdata.status === false){
|
||||
showMsg(rdata.msg,function(){
|
||||
upyunApi();
|
||||
},{icon:2},2000);
|
||||
return;
|
||||
}
|
||||
|
||||
var mlist = rdata.data;
|
||||
// console.log(mlist);
|
||||
var listBody = ''
|
||||
var listFiles = ''
|
||||
for(var i=0;i<mlist.list.length;i++){
|
||||
if(mlist.list[i].type == null){
|
||||
listBody += '<tr><td class="cursor" onclick="osList(\''+(path+'/'+mlist.list[i].name).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
||||
<td>-</td>\
|
||||
<td>-</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', true)">删除</a></td></tr>'
|
||||
}else{
|
||||
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
||||
<td>'+toSize(mlist.list[i].size)+'</td>\
|
||||
<td>'+getFtpLocalTime(mlist.list[i].time)+'</td>\
|
||||
<td class="text-right"><a target="_blank" href="'+mlist.list[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', false)">删除</a></td></tr>'
|
||||
}
|
||||
}
|
||||
listBody += listFiles;
|
||||
|
||||
var pathLi='';
|
||||
var tmp = path.split('/')
|
||||
var pathname = '';
|
||||
var n = 0;
|
||||
for(var i=0;i<tmp.length;i++){
|
||||
if(n > 0 && tmp[i] == '') continue;
|
||||
var dirname = tmp[i];
|
||||
if(dirname == '') {
|
||||
dirname = '根目录';
|
||||
n++;
|
||||
}
|
||||
pathname += '/' + tmp[i];
|
||||
pathname = pathname.replace('//','/');
|
||||
pathLi += '<li><a title="'+pathname+'" onclick="osList(\''+pathname+'\')">'+dirname+'</a></li>';
|
||||
}
|
||||
var um = 1;
|
||||
if(tmp[tmp.length-1] == '') um = 2;
|
||||
var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
|
||||
$('#myPath').val(path);
|
||||
$(".upyunCon .place-input ul").html(pathLi);
|
||||
$(".upyunlist .list-list").html(listBody);
|
||||
|
||||
upPathLeft();
|
||||
|
||||
$('#backBtn').unbind().click(function() {
|
||||
osList(backPath);
|
||||
});
|
||||
|
||||
$('.upyunCon .refreshBtn').unbind().click(function(){
|
||||
osList(path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//计算当前目录偏移
|
||||
function upPathLeft(){
|
||||
var UlWidth = $(".place-input ul").width();
|
||||
var SpanPathWidth = $(".place-input").width() - 20;
|
||||
var Ml = UlWidth - SpanPathWidth;
|
||||
if(UlWidth > SpanPathWidth ){
|
||||
$(".place-input ul").css("left",-Ml)
|
||||
}
|
||||
else{
|
||||
$(".place-input ul").css("left",0)
|
||||
}
|
||||
}
|
||||
// $('.layui-layer-page').css('height','670px');
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 254 B |
@@ -1,28 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('clean');">服务</p>
|
||||
<p onclick="pluginConfig('clean');">配置修改</p>
|
||||
<p onclick="pluginLogs('clean',null,'run_log');">运行日志</p>
|
||||
<p onclick="pRead()">说明</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
pluginService('clean');
|
||||
|
||||
|
||||
function pRead(){
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>启动后,加入到计划中[2:30]执行。</li>';
|
||||
readme += '<li>【*】代表要删除。</li>';
|
||||
readme += '<li>添加/删除清除日志,可在`配置修改`中添加/删除。</li>';
|
||||
readme += '<li>如果是目录,会寻找【.log】后缀的文件清空。</li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
</script>
|
||||
@@ -1,227 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'clean'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
if app_debug:
|
||||
return '/tmp/' + getPluginName()
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/clean.conf"
|
||||
return path
|
||||
|
||||
|
||||
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 getLockFile():
|
||||
return getServerDir() + "/installed_lock.pl"
|
||||
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + "/clean.log"
|
||||
|
||||
|
||||
def status():
|
||||
initConf()
|
||||
if os.path.exists(getLockFile()):
|
||||
return "start"
|
||||
return 'stop'
|
||||
|
||||
|
||||
def initConf():
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
content = ""
|
||||
|
||||
clog = [
|
||||
"/var/spool/clientmqueue/*",
|
||||
"/var/log/cron-*",
|
||||
"/var/log/maillog-*",
|
||||
"/var/log/secure-*",
|
||||
"/var/log/spooler-*",
|
||||
"/var/log/yum.log-*",
|
||||
"/var/log/messages-*",
|
||||
"/var/log/btmp-*",
|
||||
"/var/log/audit/audit.log.*",
|
||||
"/var/log/rhsm/rhsm.log-*",
|
||||
"/var/log/rhsm/rhsmcertd.log-*",
|
||||
"/tmp/yum_save_*",
|
||||
"/tmp/tmp.*",
|
||||
]
|
||||
for i in clog:
|
||||
content += i + "\n"
|
||||
|
||||
# 常用日志
|
||||
clogcom = [
|
||||
"/var/log/messages",
|
||||
"/var/log/btmp",
|
||||
"/var/log/wtmp",
|
||||
"/var/log/secure",
|
||||
"/var/log/lastlog",
|
||||
"/var/log/cron",
|
||||
"/www/server/cron"
|
||||
]
|
||||
for i in clogcom:
|
||||
if os.path.exists(i):
|
||||
content += i + "\n"
|
||||
|
||||
# 清理日志
|
||||
rootDir = "/var/log"
|
||||
|
||||
l = os.listdir(rootDir)
|
||||
for x in range(len(l)):
|
||||
abspath = rootDir + "/" + l[x]
|
||||
content += abspath + "\n"
|
||||
mw.writeFile(conf, content)
|
||||
|
||||
|
||||
def start():
|
||||
initConf()
|
||||
|
||||
lock_file = getLockFile()
|
||||
if not os.path.exists(lock_file):
|
||||
mw.writeFile(lock_file, "")
|
||||
|
||||
import tool_task
|
||||
tool_task.createBgTask()
|
||||
return 'ok'
|
||||
|
||||
return 'fail'
|
||||
|
||||
|
||||
def stop():
|
||||
initConf()
|
||||
lock_file = getLockFile()
|
||||
if os.path.exists(lock_file):
|
||||
os.remove(lock_file)
|
||||
import tool_task
|
||||
tool_task.removeBgTask()
|
||||
return 'ok'
|
||||
|
||||
return 'fail'
|
||||
|
||||
|
||||
def reload():
|
||||
return 'ok'
|
||||
|
||||
|
||||
def get_filePath_fileName_fileExt(filename):
|
||||
(filepath, tempfilename) = os.path.split(filename)
|
||||
(shotname, extension) = os.path.splitext(tempfilename)
|
||||
return filepath, shotname, extension
|
||||
|
||||
|
||||
def cleanFileLog(path):
|
||||
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
|
||||
if extension == ".log":
|
||||
cmd = "echo \"\" > " + path
|
||||
tmp = mw.execShell(cmd)
|
||||
if tmp[1] != "":
|
||||
cmd += " | error:" + tmp[1].strip()
|
||||
print(cmd)
|
||||
|
||||
|
||||
def cleanSelfFileLog(path):
|
||||
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
|
||||
if extension == ".log":
|
||||
cmd = "echo \"\" > " + path
|
||||
tmp = mw.execShell(cmd)
|
||||
if tmp[1] != "":
|
||||
cmd += " | error:" + tmp[1].strip()
|
||||
print(cmd)
|
||||
|
||||
|
||||
def cleanDirLog(path):
|
||||
l = os.listdir(path)
|
||||
for x in range(len(l)):
|
||||
abspath = path + "/" + l[x]
|
||||
if os.path.isfile(abspath):
|
||||
cleanFileLog(abspath)
|
||||
if os.path.isdir(abspath):
|
||||
cleanDirLog(abspath)
|
||||
|
||||
|
||||
def cleanLog():
|
||||
conf = getConf()
|
||||
clist = mw.readFile(conf).strip()
|
||||
clist = clist.split("\n")
|
||||
|
||||
for x in clist:
|
||||
abspath = x.strip()
|
||||
|
||||
if abspath.find('*') > 1:
|
||||
cmd = 'rm -rf ' + abspath
|
||||
print(cmd)
|
||||
data = mw.execShell(cmd)
|
||||
# print(data)
|
||||
continue
|
||||
|
||||
if os.path.exists(abspath):
|
||||
if os.path.isfile(abspath):
|
||||
cleanSelfFileLog(abspath)
|
||||
continue
|
||||
|
||||
if os.path.isdir(abspath):
|
||||
cleanDirLog(abspath)
|
||||
continue
|
||||
|
||||
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 == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'clean':
|
||||
cleanLog()
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"title":"日志清理",
|
||||
"tip":"soft",
|
||||
"name":"clean",
|
||||
"type":"运行环境",
|
||||
"ps":"日志清理",
|
||||
"versions":"1.0",
|
||||
"updates":"1.0",
|
||||
"shell":"install.sh",
|
||||
"checks":"server/clean",
|
||||
"path": "server/clean",
|
||||
"author":"clean",
|
||||
"home":"https://github.com/midoks",
|
||||
"date":"2021-11-23",
|
||||
"pid": "5"
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
# cd /www/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
|
||||
Install_app()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/clean
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/clean/index.py start
|
||||
echo "${VERSION}" > $serverPath/clean/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/clean/index.py stop
|
||||
rm -rf $serverPath/clean
|
||||
echo "Uninstall_clean" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
@@ -1,156 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'clean'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getTaskConf():
|
||||
conf = getServerDir() + "/task_config.json"
|
||||
return conf
|
||||
|
||||
|
||||
def getConfigData():
|
||||
try:
|
||||
return json.loads(mw.readFile(getTaskConf()))
|
||||
except:
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
def getConfigTpl():
|
||||
tpl = {
|
||||
"name": "",
|
||||
"task_id": -1,
|
||||
}
|
||||
return tpl
|
||||
|
||||
|
||||
def createBgTask():
|
||||
removeBgTask()
|
||||
args = {
|
||||
"period": "day",
|
||||
"hour": "0",
|
||||
"minute": "15",
|
||||
}
|
||||
createBgTaskByName(getPluginName(), args)
|
||||
|
||||
|
||||
def createBgTaskByName(name, args):
|
||||
cfg = getConfigTpl()
|
||||
_name = "[勿删]日志清理[" + name + "]"
|
||||
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
|
||||
if res:
|
||||
return True
|
||||
|
||||
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
|
||||
res = mw.M("crontab").field("id, name").where(
|
||||
"id=?", (cfg["task_id"],)).find()
|
||||
if res and res["id"] == cfg["task_id"]:
|
||||
print("计划任务已经存在!")
|
||||
return True
|
||||
import crontab_api
|
||||
api = crontab_api.crontab_api()
|
||||
|
||||
period = args['period']
|
||||
_hour = ''
|
||||
_minute = ''
|
||||
_where1 = ''
|
||||
_type_day = "day"
|
||||
if period == 'day':
|
||||
_type_day = 'day'
|
||||
_hour = args['hour']
|
||||
_minute = args['minute']
|
||||
elif period == 'minute-n':
|
||||
_type_day = 'minute-n'
|
||||
_where1 = args['minute-n']
|
||||
_minute = ''
|
||||
|
||||
mw_dir = mw.getRunDir()
|
||||
cmd = '''
|
||||
mw_dir=%s
|
||||
rname=%s
|
||||
plugin_path=%s
|
||||
script_path=%s
|
||||
logs_file=$plugin_path/${rname}.log
|
||||
''' % (mw_dir, name, getServerDir(), getPluginDir())
|
||||
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
|
||||
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
|
||||
cmd += 'echo "python3 $script_path/index.py clean >> $logs_file 2>&1"' + "\n"
|
||||
cmd += 'cd $mw_dir && python3 $script_path/index.py clean >> $logs_file 2>&1' + "\n"
|
||||
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
|
||||
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
|
||||
|
||||
params = {
|
||||
'name': _name,
|
||||
'type': _type_day,
|
||||
'week': "",
|
||||
'where1': _where1,
|
||||
'hour': _hour,
|
||||
'minute': _minute,
|
||||
'save': "",
|
||||
'backup_to': "",
|
||||
'stype': "toShell",
|
||||
'sname': '',
|
||||
'sbody': cmd,
|
||||
'urladdress': '',
|
||||
}
|
||||
|
||||
task_id = api.add(params)
|
||||
if task_id > 0:
|
||||
cfg["task_id"] = task_id
|
||||
cfg["name"] = name
|
||||
|
||||
_dd = getConfigData()
|
||||
_dd.append(cfg)
|
||||
mw.writeFile(getTaskConf(), json.dumps(_dd))
|
||||
|
||||
|
||||
def removeBgTask():
|
||||
cfg_list = getConfigData()
|
||||
for x in range(len(cfg_list)):
|
||||
cfg = cfg_list[x]
|
||||
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
|
||||
res = mw.M("crontab").field("id, name").where(
|
||||
"id=?", (cfg["task_id"],)).find()
|
||||
if res and res["id"] == cfg["task_id"]:
|
||||
import crontab_api
|
||||
api = crontab_api.crontab_api()
|
||||
data = api.delete(cfg["task_id"])
|
||||
if data[0]:
|
||||
cfg["task_id"] = -1
|
||||
cfg_list[x] = cfg
|
||||
mw.writeFile(getTaskConf(), '[]')
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
action = sys.argv[1]
|
||||
if action == "remove":
|
||||
removeBgTask()
|
||||
elif action == "add":
|
||||
createBgTask()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Executable
+550
@@ -0,0 +1,550 @@
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
# coding: utf-8
|
||||
|
||||
import time
|
||||
import psutil
|
||||
import random
|
||||
import os
|
||||
import urllib
|
||||
import binascii
|
||||
import json
|
||||
import public
|
||||
import re
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print status()
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "最流行的SVN代码共享管理软件",
|
||||
"shell": "install.sh",
|
||||
"name": "csvn",
|
||||
"title": "CSVN",
|
||||
"versions": ["5.1"],
|
||||
"updates":["5.1.4"],
|
||||
"tip": "soft",
|
||||
"checks": "server/csvn",
|
||||
"author": "midoks",
|
||||
"date": "2017-04-01",
|
||||
"home": "https://www.collab.net",
|
||||
"type": "SVN代码共享管理软件",
|
||||
"pid": "3"
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/bt_install.pl
|
||||
|
||||
|
||||
CSVN_SOURCE='https://github.com/midoks/mdserver-web/releases/download/init/CollabNetSubversionEdge-5.1.4_linux-x86_64.tar.xz'
|
||||
|
||||
Install_csvn()
|
||||
{
|
||||
mkdir -p $serverPath/tmp
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if [ ! -f $serverPath/tmp/csvn.tar.xz ];then
|
||||
wget -O $serverPath/so/csvn.tar.xz ${CSVN_SOURCE}
|
||||
fi
|
||||
|
||||
cd $serverPath/tmp && tar -Jxf $serverPath/tmp/csvn.tar.xz
|
||||
mv $serverPath/tmp/csvn $serverPath/csvn
|
||||
|
||||
echo '安装完成' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_csvn()
|
||||
{
|
||||
rm -rf $serverPath/csvn
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
host=$2
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_csvn
|
||||
else
|
||||
Uninstall_csvn
|
||||
fi
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,25 +0,0 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('data_query');">服务</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(300);
|
||||
resetPluginWinWidth(380);
|
||||
pluginService('data_query', $('.plugin_version').attr('version'));
|
||||
</script>
|
||||
@@ -1,97 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'data_query'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
def appOp(method):
|
||||
return 'ok'
|
||||
|
||||
|
||||
|
||||
def start():
|
||||
return appOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return appOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = appOp('restart')
|
||||
return status
|
||||
|
||||
def reload():
|
||||
return appOp('reload')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"hook":[
|
||||
{
|
||||
"tag":"menu",
|
||||
"menu": {
|
||||
"title":"数据管理",
|
||||
"name":"data_query",
|
||||
"path":"static/html/index.html",
|
||||
"css_path":"static/css/data.css",
|
||||
"js_path":"static/js/app.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag":"global_static",
|
||||
"global_static": {
|
||||
"title":"数据管理",
|
||||
"name":"data_query",
|
||||
"css_path":"static/css/ico.css"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sort": 7,
|
||||
"ps": "数据简单管理(memcached,redis,mongodb)",
|
||||
"name": "data_query",
|
||||
"title": "数据管理",
|
||||
"shell": "install.sh",
|
||||
"versions":"1.0",
|
||||
"tip": "soft",
|
||||
"checks": "server/data_query",
|
||||
"path": "server/data_query",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2024-01-22",
|
||||
"type": 0,
|
||||
"pid": "2"
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/data_query
|
||||
echo "${VERSION}" > $serverPath/data_query/version.pl
|
||||
|
||||
echo '安装完成'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf $serverPath/data_query
|
||||
echo "卸载成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
@@ -1,253 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
# https://pypi.org/project/pymemcache/
|
||||
# https://pymemcache.readthedocs.io/en/latest/getting_started.html#using-a-client-pool
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
import pymemcache
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
@singleton
|
||||
class nosqlMemcached():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 11211
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
mem_path = "{}/memcached".format(mw.getServerDir())
|
||||
if not os.path.exists(mem_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
try:
|
||||
self.__DB_CONN = pymemcache.client.base.PooledClient((self.__DB_HOST,self.__DB_PORT), max_pool_size=4)
|
||||
return self.__DB_CONN
|
||||
except pymemcache.exceptions.MemcacheError:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.getTracebackInfo()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
|
||||
result = {}
|
||||
mem_content = mw.readFile("{}/memcached/memcached.env".format(mw.getServerDir()))
|
||||
if not mem_content: return False
|
||||
|
||||
keys = ["bind", "PORT"]
|
||||
rep = 'PORT\s*=\s*(.*)'
|
||||
port_re = re.search(rep, mem_content)
|
||||
if port_re:
|
||||
result['port'] = int(port_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 11211
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMemcachedCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMemcached()
|
||||
return instance
|
||||
|
||||
def getItems(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
m_items = mem_instance.stats('items')
|
||||
|
||||
item_no = []
|
||||
for i in m_items:
|
||||
item_match = b'items:(\d*?):number'
|
||||
item_match_re = re.search(item_match, i)
|
||||
if item_match_re:
|
||||
v = item_match_re.groups()[0].strip()
|
||||
v_str = v.decode()
|
||||
if not v_str in item_no:
|
||||
item_no.append(v_str)
|
||||
|
||||
if len(item_no) == 0:
|
||||
item_no = [0]
|
||||
|
||||
result['items'] = item_no
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getKeyList(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
item_id = args['item_id']
|
||||
if item_id == '0':
|
||||
return mw.returnData(False,'ok')
|
||||
|
||||
m_items = mem_instance.stats('items')
|
||||
|
||||
item_key = 'items:%s:number' % item_id
|
||||
item_key_b = item_key.encode("utf-8")
|
||||
m_items_v = m_items[item_key_b]
|
||||
|
||||
|
||||
start = (p-1)*size
|
||||
end = start+size
|
||||
if end > m_items_v:
|
||||
end = m_items_v
|
||||
|
||||
|
||||
all_key = mem_instance.stats('cachedump', str(item_id) , str(0))
|
||||
# print(all_key)
|
||||
all_key_list = []
|
||||
cur_time_t = time.time()
|
||||
for k in all_key:
|
||||
t = {}
|
||||
t['k'] = k.decode("utf-8")
|
||||
v = all_key[k].decode("utf-8")
|
||||
v = v.strip('[').strip(']').split(';')
|
||||
t['s'] = v[0]
|
||||
cur_time = v[1].strip().split(' ')[0]
|
||||
|
||||
if int(cur_time) != 0 :
|
||||
t['t'] = int(cur_time) - int(cur_time_t)
|
||||
else:
|
||||
t['t'] = 0
|
||||
all_key_list.append(t)
|
||||
|
||||
# print(len(all_key_list))
|
||||
# print(start,end)
|
||||
return_all_key = all_key_list[start:end]
|
||||
|
||||
for x in range(len(return_all_key)):
|
||||
v = mem_instance.get(return_all_key[x]['k'])
|
||||
return_all_key[x]['v'] = v.decode('utf-8')
|
||||
|
||||
result = {}
|
||||
result['list'] = return_all_key
|
||||
result['p'] = p
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = len(all_key_list)
|
||||
page_args['tojs'] = 'memcachedGetKeyList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
result['page'] = mw.getPage(page_args)
|
||||
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def delVal(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
key = args['key']
|
||||
mem_instance.delete(key)
|
||||
return mw.returnData(True,'删除成功!')
|
||||
|
||||
def setKv(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
key = args['key']
|
||||
val = args['val']
|
||||
endtime = args['endtime']
|
||||
mem_instance.set(key, val, int(endtime))
|
||||
return mw.returnData(True,'设置成功!')
|
||||
|
||||
def clear(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
mem_instance.flush_all()
|
||||
return mw.returnData(True,'清空成功!')
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 memcached 列表
|
||||
def get_items(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.getItems(args)
|
||||
|
||||
def get_key_list(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.getKeyList(args)
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
def clear(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.clear(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMemcachedCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
|
||||
@@ -1,351 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import pymongo
|
||||
import json
|
||||
import yaml
|
||||
|
||||
from bson.objectid import ObjectId
|
||||
from bson.json_util import dumps
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
def getPluginName():
|
||||
return 'mongodb'
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/mongodb.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/config/mongodb.conf"
|
||||
return path
|
||||
|
||||
def pSqliteDb(dbname='users'):
|
||||
file = getServerDir() + '/mongodb.db'
|
||||
name = 'mongodb'
|
||||
|
||||
sql_file = getPluginDir() + '/config/mongodb.sql'
|
||||
import_sql = mw.readFile(sql_file)
|
||||
# print(sql_file,import_sql)
|
||||
md5_sql = mw.md5(import_sql)
|
||||
|
||||
import_sign = False
|
||||
save_md5_file = getServerDir() + '/import_mongodb.md5'
|
||||
if os.path.exists(save_md5_file):
|
||||
save_md5_sql = mw.readFile(save_md5_file)
|
||||
if save_md5_sql != md5_sql:
|
||||
import_sign = True
|
||||
mw.writeFile(save_md5_file, md5_sql)
|
||||
else:
|
||||
mw.writeFile(save_md5_file, md5_sql)
|
||||
|
||||
if not os.path.exists(file) or import_sql:
|
||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
||||
csql_list = import_sql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
conn.execute(csql_list[index], ())
|
||||
|
||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
||||
return conn
|
||||
|
||||
def getConfigData():
|
||||
cfg = getConf()
|
||||
# print(cfg)
|
||||
config_data = mw.readFile(cfg)
|
||||
try:
|
||||
config = yaml.safe_load(config_data)
|
||||
except:
|
||||
config = {
|
||||
"systemLog": {
|
||||
"destination": "file",
|
||||
"logAppend": True,
|
||||
"path": mw.getServerDir()+"/mongodb/log/mongodb.log"
|
||||
},
|
||||
"storage": {
|
||||
"dbPath": mw.getServerDir()+"/mongodb/data",
|
||||
"directoryPerDB": True,
|
||||
"journal": {
|
||||
"enabled": True
|
||||
}
|
||||
},
|
||||
"processManagement": {
|
||||
"fork": True,
|
||||
"pidFilePath": mw.getServerDir()+"/mongodb/log/mongodb.pid"
|
||||
},
|
||||
"net": {
|
||||
"port": 27017,
|
||||
"bindIp": "0.0.0.0"
|
||||
},
|
||||
"security": {
|
||||
"authorization": "disabled",
|
||||
"javascriptEnabled": False
|
||||
}
|
||||
}
|
||||
return config
|
||||
|
||||
def getConfPort():
|
||||
data = getConfigData()
|
||||
return data['net']['port']
|
||||
|
||||
def getConfAuth():
|
||||
data = getConfigData()
|
||||
return data['security']['authorization']
|
||||
|
||||
@singleton
|
||||
class nosqlMongodb():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 6379
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def mgdb_conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
mgdb_path = "{}/mongodb".format(mw.getServerDir())
|
||||
if not os.path.exists(mgdb_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
|
||||
auth = getConfAuth()
|
||||
port = getConfPort()
|
||||
mg_root = pSqliteDb('config').where('id=?', (1,)).getField('mg_root')
|
||||
# print(auth,self.__DB_HOST,port, self.__DB_PASS)
|
||||
try:
|
||||
if auth == 'disabled':
|
||||
self.__DB_CONN = pymongo.MongoClient(host=self.__DB_HOST, port=port, directConnection=True)
|
||||
else:
|
||||
self.__DB_CONN = pymongo.MongoClient(host=self.__DB_HOST, port=port, directConnection=True, username='root',password=mg_root)
|
||||
self.__DB_CONN.admin.command('ping')
|
||||
return self.__DB_CONN
|
||||
except pymongo.errors.ConnectionFailure:
|
||||
return False
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
self.__DB_ERR = mw.getTracebackInfo()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
result = {}
|
||||
mgdb_content = mw.readFile("{}/mongodb/mongodb.conf".format(mw.getServerDir()))
|
||||
if not mgdb_content: return False
|
||||
|
||||
keys = ["bind_ip", "port"]
|
||||
|
||||
result['host'] = '127.0.0.1'
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
ip_re = re.search(rep, mgdb_content)
|
||||
if ip_re:
|
||||
result['port'] = int(ip_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 27017
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMongodbCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMongodb()
|
||||
return instance
|
||||
|
||||
def getDbList(self, args):
|
||||
sid = args['sid']
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
doc_list = mgdb_instance.list_database_names()
|
||||
rlist = []
|
||||
for x in doc_list:
|
||||
if not x in ['admin', 'config', 'local']:
|
||||
rlist.append(x)
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getCollectionsList(self, args):
|
||||
sid = args['sid']
|
||||
name = args['name']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接.')
|
||||
|
||||
result = {}
|
||||
collections = mgdb_instance[name].list_collection_names()
|
||||
result['collections'] = collections
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDataList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
collection = args['collection']
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
db_instance = mgdb_instance[db]
|
||||
collection_instance = db_instance[collection]
|
||||
|
||||
start_index = (p - 1) * size
|
||||
end_index = p * size
|
||||
args_where = args['where']
|
||||
|
||||
where = {}
|
||||
if 'field' in args_where:
|
||||
mg_field = args_where['field']
|
||||
|
||||
if mg_field == '_id':
|
||||
mg_value = ObjectId(args_where['value'])
|
||||
where[mg_field] = mg_value
|
||||
else:
|
||||
mg_value = args_where['value']
|
||||
where[mg_field] = re.compile(mg_value)
|
||||
|
||||
# print(where)
|
||||
result = collection_instance.find(where).skip(start_index).limit(size).sort('_id',-1)
|
||||
count = collection_instance.count_documents(where)
|
||||
d = []
|
||||
for document in result:
|
||||
d.append(document)
|
||||
|
||||
doc_str_json = dumps(d)
|
||||
result = json.loads(doc_str_json)
|
||||
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['tojs'] = 'mongodbDataList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['list'] = result
|
||||
rdata['count'] = count
|
||||
|
||||
rdata['soso_field'] = ''
|
||||
if 'field' in args_where:
|
||||
rdata['soso_field'] = args_where['field']
|
||||
|
||||
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def delById(self,args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
collection = args['collection']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
db_instance = mgdb_instance[db]
|
||||
collection_instance = db_instance[collection]
|
||||
|
||||
_id = args['_id']
|
||||
result = collection_instance.delete_one({"_id": ObjectId(_id)})
|
||||
|
||||
return mw.returnData(True,'文档删除【%d】个成功!' % result.deleted_count)
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 mongodb databases 列表
|
||||
def get_db_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getDbList(args)
|
||||
|
||||
# 获取 mongodb collections 列表
|
||||
def get_collections_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getCollectionsList(args)
|
||||
|
||||
def get_data_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getDataList(args)
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def batch_del_val(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.batchDelVal(args)
|
||||
|
||||
def clear_flushdb(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.clearFlushDB(args)
|
||||
|
||||
def del_by_id(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.delById(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMongodbCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
@@ -1,347 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import redis
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
# def getPluginName():
|
||||
# return 'data_query'
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
@singleton
|
||||
class nosqlRedis():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 6379
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def redis_conn(self, db_idx=0):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
redis_path = "{}/redis".format(mw.getServerDir())
|
||||
if not os.path.exists(redis_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PASS = self.__config['requirepass']
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
|
||||
# print(self.__DB_HOST,self.__DB_PORT, self.__DB_PASS)
|
||||
try:
|
||||
redis_pool = redis.ConnectionPool(host=self.__DB_HOST, port=self.__DB_PORT, password=self.__DB_PASS, db=db_idx, socket_timeout=3)
|
||||
self.__DB_CONN = redis.Redis(connection_pool=redis_pool)
|
||||
self.__DB_CONN.ping()
|
||||
return self.__DB_CONN
|
||||
except redis.exceptions.ConnectionError:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.getTracebackInfo()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
|
||||
result = {}
|
||||
redis_conf = mw.readFile("{}/redis/redis.conf".format(mw.getServerDir()))
|
||||
if not redis_conf: return False
|
||||
|
||||
keys = ["bind", "port", "timeout", "maxclients", "databases", "requirepass", "maxmemory"]
|
||||
for k in keys:
|
||||
v = ""
|
||||
rep = "\n%s\s+(.+)" % k
|
||||
group = re.search(rep, redis_conf)
|
||||
if not group:
|
||||
if k == "maxmemory":
|
||||
v = "0"
|
||||
if k == "maxclients":
|
||||
v = "10000"
|
||||
if k == "requirepass":
|
||||
v = ""
|
||||
else:
|
||||
if k == "maxmemory":
|
||||
v = int(group.group(1).strip("mb"))
|
||||
else:
|
||||
v = group.group(1)
|
||||
result[k] = v
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlRedisCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlRedis()
|
||||
return instance
|
||||
|
||||
def getList(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(0)
|
||||
if redis_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
is_cluster = redis_info.get("cluster_enabled", 0)
|
||||
if is_cluster != 0:
|
||||
return mw.returnData(False, "当前不支持连接redis集群!")
|
||||
|
||||
db_num = 16
|
||||
if sid != 0:
|
||||
db_num = 1000
|
||||
|
||||
result = []
|
||||
for x in range(0, db_num):
|
||||
data = {}
|
||||
data['id'] = x
|
||||
data['name'] = 'DB{}'.format(x)
|
||||
try:
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(x)
|
||||
data['keynum'] = redis_instance.dbsize()
|
||||
result.append(data)
|
||||
except:
|
||||
break
|
||||
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDbKeyList(self, args):
|
||||
p = 1
|
||||
size = 10
|
||||
|
||||
if not 'sid' in args:
|
||||
return mw.returnData(False, "缺少参数!sid")
|
||||
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
if p < 1:
|
||||
p = 1
|
||||
if p > 10:
|
||||
p = 10
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
search = '*'
|
||||
if 'search' in args and args['search'] != '':
|
||||
search = args['search']
|
||||
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
total = redis_instance.dbsize()
|
||||
|
||||
if search != '*':
|
||||
keylist = redis_instance.keys(search)
|
||||
total = len(keylist)
|
||||
else:
|
||||
keys = redis_instance.scan(cursor=0, match="{}".format(search), count=p*size)
|
||||
keylist = keys[1]
|
||||
|
||||
slist = keylist[(p - 1) * size:p*size]
|
||||
|
||||
items = []
|
||||
for key in slist:
|
||||
item = {}
|
||||
try:
|
||||
item['name'] = key.decode()
|
||||
except Exception as e:
|
||||
item['name'] = str(key)
|
||||
|
||||
item['endtime'] = redis_instance.ttl(key)
|
||||
item['type'] = redis_instance.type(key).decode()
|
||||
|
||||
if item['type'] == 'string':
|
||||
try:
|
||||
item['val'] = redis_instance.get(key).decode()
|
||||
except Exception as e:
|
||||
item['val'] = str(redis_instance.get(key))
|
||||
elif item['type'] == 'hash':
|
||||
if redis_instance.hlen(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.hlen(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.hgetall(key))
|
||||
elif item['type'] == 'list':
|
||||
if redis_instance.llen(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.llen(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.lrange(key, 0, -1))
|
||||
elif item['type'] == 'set':
|
||||
if redis_instance.scard(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.scard(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.smembers(key))
|
||||
elif item['type'] == 'zset':
|
||||
if redis_instance.zcard(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.zcard(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.zrange(key, 0, -1, withscores=True))
|
||||
else:
|
||||
item['val'] = ''
|
||||
|
||||
try:
|
||||
item['len'] = redis_instance.strlen(key)
|
||||
except:
|
||||
item['len'] = len(item['val'])
|
||||
items.append(item)
|
||||
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = total
|
||||
page_args['tojs'] = 'redisGetKeyList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['data'] = items
|
||||
return mw.returnData(True,'ok',rdata)
|
||||
|
||||
def setKv(self,args):
|
||||
if not 'name' in args:
|
||||
return mw.returnData(False, "缺少参数!name")
|
||||
if not 'val' in args:
|
||||
return mw.returnData(False, "缺少参数!val")
|
||||
if not 'idx' in args:
|
||||
return mw.returnData(False, "缺少参数!idx")
|
||||
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
|
||||
name = args["name"]
|
||||
val = args["val"]
|
||||
endtime = args["endtime"]
|
||||
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能写操作!')
|
||||
|
||||
if endtime != '0':
|
||||
redis_instance.set(name, val, int(endtime))
|
||||
else:
|
||||
redis_instance.set(name, val)
|
||||
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def delVal(self, args):
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
name = args["name"]
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能删除操作!')
|
||||
|
||||
redis_instance.delete(name)
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def batchDelVal(self, args):
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
keys = args["keys"]
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能删除操作!')
|
||||
|
||||
for k in keys:
|
||||
redis_instance.delete(k)
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def clearFlushDB(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
idxs = args['idxs']
|
||||
|
||||
for idx in idxs:
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能清空操作!')
|
||||
|
||||
redis_instance.flushdb()
|
||||
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 redis databases 列表
|
||||
def get_list(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.getList(args)
|
||||
|
||||
# 获取 redis key 列表
|
||||
def get_dbkey_list(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.getDbKeyList(args)
|
||||
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def batch_del_val(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.batchDelVal(args)
|
||||
|
||||
def clear_flushdb(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.clearFlushDB(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlRedis()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import pymongo
|
||||
import json
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMySQL():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 3306
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
__DB_SOCKET = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
my_path = "{}/mysql".format(mw.getServerDir())
|
||||
if not os.path.exists(my_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
# print(self.__config)
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
self.__DB_USER = self.__config['username']
|
||||
self.__DB_PASS = self.__config['password']
|
||||
self.__DB_SOCKET = self.__config['socket']
|
||||
|
||||
try:
|
||||
|
||||
db = mw.getMyORM()
|
||||
db.setPort(self.__DB_PORT)
|
||||
db.setPwd(self.__DB_PASS)
|
||||
db.setUser(self.__DB_USER)
|
||||
if self.__DB_SOCKET != '':
|
||||
db.setSocket(self.__DB_SOCKET)
|
||||
|
||||
return db
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.get_error_info()
|
||||
return False
|
||||
|
||||
def sqliteDb(self,dbname='databases'):
|
||||
my_root_path = mw.getServerDir() +'/mysql'
|
||||
name = 'mysql'
|
||||
conn = mw.M(dbname).dbPos(my_root_path, name)
|
||||
return conn
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
result = {}
|
||||
|
||||
|
||||
my_cnf_path = "{}/mysql/etc/my.cnf".format(mw.getServerDir())
|
||||
my_content = mw.readFile(my_cnf_path)
|
||||
if not my_content: return False
|
||||
|
||||
mysql_pass = self.sqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||
result['password'] = mysql_pass
|
||||
result['username'] = 'root'
|
||||
keys = ["bind_ip", "port"]
|
||||
|
||||
result['host'] = '127.0.0.1'
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
|
||||
port_re = re.search(rep, my_content)
|
||||
if port_re:
|
||||
result['port'] = int(port_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 3306
|
||||
|
||||
socket_rep = 'socket\s*=\s*(.*)'
|
||||
socket_re = re.search(socket_rep, my_content)
|
||||
if socket_re:
|
||||
result['socket'] = socket_re.groups()[0].strip()
|
||||
else:
|
||||
result['socket'] = ''
|
||||
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMySQLCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMySQL()
|
||||
return instance
|
||||
|
||||
def getDbList(self, args):
|
||||
sid = args['sid']
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
db_list = my_instance.query('show databases')
|
||||
rlist = []
|
||||
for x in db_list:
|
||||
if not x['Database'] in ['information_schema', 'mysql', 'performance_schema','sys']:
|
||||
rlist.append(x['Database'])
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getTableList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
sql = "select * from information_schema.tables where table_schema = '"+db+"'"
|
||||
table_list = my_instance.query(sql)
|
||||
# print(table_list)
|
||||
|
||||
rlist = []
|
||||
for x in table_list:
|
||||
# print(x['TABLE_NAME'])
|
||||
rlist.append(x['TABLE_NAME'])
|
||||
result = {}
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDataList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
table = args['table']
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
start_index = (p - 1) * size
|
||||
|
||||
|
||||
args_where = {}
|
||||
where_sql = ''
|
||||
if 'where' in args:
|
||||
args_where = args['where']
|
||||
if 'field' in args_where:
|
||||
if args_where['field'] == 'id' or args_where['field'].find('id')>-1:
|
||||
where_sql = ' where '+args_where['field'] + " = '"+args_where['value']+"' "
|
||||
else:
|
||||
where_sql = ' where '+args_where['field'] + " like '%"+args_where['value']+"%' "
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
my_instance.setDbName(db)
|
||||
sql = 'select count(*) as num from ' + table + where_sql
|
||||
# print(sql)
|
||||
count_result = my_instance.query(sql)
|
||||
count = count_result[0]['num']
|
||||
|
||||
|
||||
sql = 'select * from ' + table + where_sql + ' limit '+str(start_index)+',10';
|
||||
# print(sql)
|
||||
result = my_instance.query(sql)
|
||||
|
||||
for i in range(len(result)):
|
||||
for f in result[i]:
|
||||
result[i][f] = str(result[i][f])
|
||||
|
||||
# print(result)
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['tojs'] = 'mysqlGetDataList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['list'] = result
|
||||
rdata['count'] = count
|
||||
|
||||
rdata['soso_field'] = ''
|
||||
if 'field' in args_where:
|
||||
rdata['soso_field'] = args_where['field']
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showProcessList(self,args):
|
||||
sql = 'show processlist';
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showStatusList(self,args):
|
||||
sql = 'show status';
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showStatsList(self, args):
|
||||
sql = "show status like 'Com_%'";
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 mysql 列表
|
||||
def get_db_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getDbList(args)
|
||||
|
||||
# 获取 mysql 列表
|
||||
def get_table_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getTableList(args)
|
||||
|
||||
def get_data_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getDataList(args)
|
||||
|
||||
def get_proccess_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showProcessList(args)
|
||||
|
||||
def get_status_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showStatusList(args)
|
||||
|
||||
def get_stats_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showStatsList(args)
|
||||
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMySQLCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
@@ -1,48 +0,0 @@
|
||||
.main-content .safe {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mask_layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgb(255 255 255 / 60%);
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
.mask_layer .prompt_description {
|
||||
width: 350px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-top: -25px;
|
||||
margin-left: -175px;
|
||||
background: #fff;
|
||||
box-shadow: 1px 1px 50px rgb(0 0 0 / 30%);
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#mongodb_search xm-select {
|
||||
min-height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
#mongodb_search xm-select .xm-label .xm-label-block{
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#mongodb td:last-child, th:last-child {
|
||||
width: 44px;
|
||||
position:sticky;
|
||||
right:0; /* 首行永远固定在左侧 */
|
||||
z-index:1;
|
||||
background-color:white;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
/* menu start */
|
||||
.menu .current .menu_plugin_data_query:hover {
|
||||
background-image: url("/plugins/file?name=data_query&f=ico.png");
|
||||
}
|
||||
|
||||
.menu .menu_plugin_data_query {
|
||||
background-image: url("/plugins/file?name=data_query&f=ico.png");
|
||||
}
|
||||
|
||||
/* menu end */
|
||||
@@ -1,294 +0,0 @@
|
||||
<div class="main-content" style="min-height: 389px;">
|
||||
<div class="container-fluid" style="padding-bottom: 50px;">
|
||||
<div id="cutTab" class="pos-box bgw mtb15" style="height:45px">
|
||||
<div class="tab-list">
|
||||
<div class="tabs-item active" data-name="redis">Redis</div>
|
||||
<div class="tabs-item" data-name="mongodb">Mongodb</div>
|
||||
<div class="tabs-item" data-name="memcached">Memcached</div>
|
||||
<div class="tabs-item" data-name="mysql">MySQL</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view safe" style="overflow: hidden;">
|
||||
|
||||
<div class="mask_layer" style="display:none;">
|
||||
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft">点击安装</a></div>
|
||||
</div>
|
||||
|
||||
<!-- mysql start -->
|
||||
<!-- show w-full -->
|
||||
<div class="tab-con hide" id="mysql" style="padding: 0px;">
|
||||
|
||||
<div class="col-md-12" style="padding: 0px;overflow: hidden;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<div class="server_list" style="float:left;">
|
||||
<select name="sid" class="bt-input-text c5 mr5">
|
||||
<option value="0">本地服务器</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mysql_db_list" style="float:left;">
|
||||
<select name="mysql_db" class="bt-input-text c5 mr5">
|
||||
<option value="0">数据库空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mysql_table_list" style="float:left;">
|
||||
<select name="mysql_table" class="bt-input-text c5 mr5">
|
||||
<option value="0">数据表空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field" style="float:left;">
|
||||
<select name="mysql_field_key" class="bt-input-text c5 mr5" style="width:80px;">
|
||||
<option value="0">无字段</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="value" style="float:left;">
|
||||
<input name="mysql_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
|
||||
</div>
|
||||
|
||||
<button type="button" class="mysql_find btn btn-success btn-sm mr5 ml5" style="float:right;">
|
||||
<span>查找</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="position: relative;">
|
||||
<div id="mysql_table" class="mysql_table divtable mtb10">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mysql_list_page page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12" style="padding-left: 3px;">
|
||||
<div id="mysql_list_tab" style="padding-top:0px;">
|
||||
<div class="tab-nav">
|
||||
<span data-name="proccess" class="on">进程</span>
|
||||
<span data-name="status" class="">状态</span>
|
||||
<span data-name="stats" class="">统计</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position: relative;">
|
||||
<div id="mysql_ot_table" class="divtable">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- mysql end -->
|
||||
|
||||
<!-- mongodb start -->
|
||||
<!-- show w-full -->
|
||||
<div class="tab-con hide" id="mongodb" style="padding: 0px;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
|
||||
<div class="field" style="float:left;">
|
||||
<select name="mongodb_field_key" class="bt-input-text c5 mr5" style="width:80px;">
|
||||
<option value="0">无字段</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="value" style="float:left;">
|
||||
<input name="mongodb_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
|
||||
</div>
|
||||
|
||||
<button type="button" class="mongodb_find btn btn-success btn-sm mr5 ml5" style="float:right;">
|
||||
<span>查找</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="server_list" style="float:left;">
|
||||
<select name="sid" class="bt-input-text c5 mr5">
|
||||
<option value="0">本地服务器</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="db_list" style="float:left;">
|
||||
<select name="db" class="bt-input-text c5 mr5">
|
||||
<option value="0">空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search" id="mongodb_search"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position: relative;">
|
||||
|
||||
<div id="mongodb_table" class="mongodb_table divtable mtb10">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mongodb_list_page page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- mongodb end -->
|
||||
|
||||
<!-- redis start -->
|
||||
<div class="tab-con show w-full" id="redis" style="padding: 0px;">
|
||||
<div id="redis_ctr" style="position: relative;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<button id="redis_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
|
||||
<span>添加key</span>
|
||||
</button>
|
||||
<button id="redis_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
|
||||
<span>清空数据库</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="redis_list_tab" style="padding-top:10px;">
|
||||
<div class="tab-nav">
|
||||
<!-- <span data-id="0" class="on">DB0(0)</span> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left"></div>
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="search">
|
||||
<input id="redis_ksearch" type="text" class="search_input" placeholder="请输入键名称">
|
||||
<span id="redis_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divtable mtb10 redis_table_content">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
|
||||
<th><span>键</span></th>
|
||||
<th><span>值</span></th>
|
||||
<th><span>数据类型</span></th>
|
||||
<th><span>数据长度</span></th>
|
||||
<th><span>有效期</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_bottom">
|
||||
<div class="pull-left">
|
||||
<button id="redis_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="page redis_list_page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- redis end -->
|
||||
|
||||
<!-- memcached start -->
|
||||
<div class="tab-con hide" id="memcached" style="padding: 0px;">
|
||||
|
||||
<div id="memcached_ctr" style="position: relative;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<button id="memcached_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
|
||||
<span>添加key</span>
|
||||
</button>
|
||||
<button id="memcached_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
|
||||
<span>清空</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="item_list" style="float:left;">
|
||||
<select name="item" class="bt-input-text c5 mr5">
|
||||
<option value="0">空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search">
|
||||
<input id="memcached_ksearch" type="text" class="search_input" placeholder="请输入键名称">
|
||||
<span id="memcached_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="divtable mtb10 memcached_table_content">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
|
||||
<th><span>键</span></th>
|
||||
<th><span>值</span></th>
|
||||
<th><span>数据长度</span></th>
|
||||
<th><span>有效期</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_bottom">
|
||||
<div class="pull-left">
|
||||
<button id="memcached_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="page memcached_list_page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- memcached end -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,58 +0,0 @@
|
||||
<style type="text/css">
|
||||
|
||||
.docker-sub {
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.docker-sub .on {
|
||||
border-bottom: 2px solid #20a53a;
|
||||
color: #20a53a;
|
||||
font-weight: bold;
|
||||
font-family: "宋体";
|
||||
}
|
||||
.docker-sub span {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
height: 30px;
|
||||
padding: 0 25px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.docker-environments {
|
||||
resize: none;
|
||||
width: 330px;
|
||||
height: 80px;
|
||||
line-height: 20px;
|
||||
padding: 5px 8px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('docker');">服务</p>
|
||||
<p onclick="pluginInitD('docker');">自启动</p>
|
||||
<p onclick="dockerConList();">容器列表</p>
|
||||
<p onclick="dockerImageList();">镜像列表</p>
|
||||
<p onclick="dockerImageOutput();">镜像导出</p>
|
||||
<p onclick="dockerIpList();">IP地址池</p>
|
||||
<p onclick="repoList();">仓库</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinWidth(800);
|
||||
resetPluginWinHeight(400);
|
||||
$.getScript( "/plugins/file?name=docker&f=js/docker.js", function(){
|
||||
pluginService('docker', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
@@ -1,860 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
import docker
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getDClient():
|
||||
try:
|
||||
client = docker.from_env()
|
||||
except Exception as e:
|
||||
client = docker.DockerClient(
|
||||
base_url='unix:///Users/midoks/.docker/run/docker.sock')
|
||||
return client
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'docker'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/redis.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/config/redis.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(self, data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
print(data[i])
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|grep docker |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def initDreplace():
|
||||
return ''
|
||||
|
||||
|
||||
def dockerOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
data = mw.execShell('systemctl ' + method + ' docker')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
return 'fail'
|
||||
|
||||
|
||||
def start():
|
||||
return dockerOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return dockerOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = dockerOp('restart')
|
||||
|
||||
log_file = runLog()
|
||||
mw.execShell("echo '' > " + log_file)
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return dockerOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
# UTC时间转换为时间戳
|
||||
|
||||
|
||||
def utc_to_local(utc_time_str, utc_format='%Y-%m-%dT%H:%M:%S'):
|
||||
import pytz
|
||||
import datetime
|
||||
import time
|
||||
local_tz = pytz.timezone('Asia/Chongqing')
|
||||
local_format = "%Y-%m-%d %H:%M"
|
||||
utc_dt = datetime.datetime.strptime(utc_time_str, utc_format)
|
||||
local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
|
||||
time_str = local_dt.strftime(local_format)
|
||||
return int(time.mktime(time.strptime(time_str, local_format)))
|
||||
|
||||
|
||||
def conList():
|
||||
c = getDClient()
|
||||
clist = c.containers.list(all=True)
|
||||
conList = []
|
||||
for con in clist:
|
||||
tmp = con.attrs
|
||||
tmp['Created'] = utc_to_local(tmp['Created'].split('.')[0])
|
||||
conList.append(tmp)
|
||||
return conList
|
||||
|
||||
|
||||
def conListData():
|
||||
try:
|
||||
clist = conList()
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '未开启Docker')
|
||||
return mw.returnJson(True, 'ok', clist)
|
||||
|
||||
|
||||
def dockerRemoveCon():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['Hostname'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
Hostname = args['Hostname']
|
||||
|
||||
c = getDClient()
|
||||
try:
|
||||
conFind = c.containers.get(Hostname)
|
||||
try:
|
||||
path_list = conFind.attrs['GraphDriver'][
|
||||
'Data']['LowerDir'].split(':')
|
||||
for i in path_list:
|
||||
mw.execShell('chattr -R -i %s' % i)
|
||||
except:
|
||||
pass
|
||||
conFind.remove(force=True)
|
||||
return mw.returnJson(True, '成功删除!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
||||
|
||||
|
||||
def dockerLogCon():
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['Hostname'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
Hostname = args['Hostname']
|
||||
|
||||
c = getDClient()
|
||||
try:
|
||||
conFind = c.containers.get(Hostname)
|
||||
if not conFind:
|
||||
return mw.returnJson(False, 'The specified container does not exist!')
|
||||
log = conFind.logs()
|
||||
if not isinstance(log, str):
|
||||
log = log.decode()
|
||||
return mw.returnJson(True, log)
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, 'Get Logs failed')
|
||||
|
||||
|
||||
def dockerRunCon():
|
||||
# 启动容器
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['Hostname'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
Hostname = args['Hostname']
|
||||
c = getDClient()
|
||||
try:
|
||||
conFind = c.containers.get(Hostname)
|
||||
if not conFind:
|
||||
return mw.returnJson(False, 'The specified container does not exist!')
|
||||
conFind.start()
|
||||
return mw.returnJson(True, '启动成功!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '启动失败!' + str(ex))
|
||||
|
||||
|
||||
def dockerStopCon():
|
||||
# 停止容器
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['Hostname'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
Hostname = args['Hostname']
|
||||
c = getDClient()
|
||||
try:
|
||||
conFind = c.containers.get(Hostname)
|
||||
if not conFind:
|
||||
return mw.returnJson(False, 'The specified container does not exist!')
|
||||
conFind.stop()
|
||||
return mw.returnJson(True, '停止成功!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '停止失败!' + str(ex))
|
||||
|
||||
|
||||
def dockerExec():
|
||||
# 容器执行命令
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['Hostname'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
Hostname = args['Hostname']
|
||||
|
||||
debug_path = 'data/debug.pl'
|
||||
if os.path.exists(debug_path):
|
||||
return mw.returnJson(False, '开发模式不能进入!')
|
||||
|
||||
c = getDClient()
|
||||
try:
|
||||
conFind = c.containers.get(Hostname)
|
||||
cmd = 'docker container exec -it %s /bin/sh' % Hostname
|
||||
return mw.returnJson(True, cmd)
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '连接失败!')
|
||||
|
||||
|
||||
def imageList():
|
||||
imageList = []
|
||||
c = getDClient()
|
||||
ilist = c.images.list()
|
||||
for image in ilist:
|
||||
tmp_attrs = image.attrs
|
||||
if len(tmp_attrs['RepoTags']) == 1:
|
||||
tmp_image = {}
|
||||
tmp_image['Id'] = tmp_attrs['Id'].split(':')[1][:12]
|
||||
tmp_image['RepoTags'] = tmp_attrs['RepoTags'][0]
|
||||
tmp_image['Size'] = tmp_attrs['Size']
|
||||
tmp_image['Labels'] = tmp_attrs['Config']['Labels']
|
||||
tmp_image['Comment'] = tmp_attrs['Comment']
|
||||
tmp_image['Created'] = utc_to_local(
|
||||
tmp_attrs['Created'].split('.')[0])
|
||||
imageList.append(tmp_image)
|
||||
else:
|
||||
for i in range(len(tmp_attrs['RepoTags'])):
|
||||
tmp_image = {}
|
||||
tmp_image['Id'] = tmp_attrs['Id'].split(':')[1][:12]
|
||||
tmp_image['RepoTags'] = tmp_attrs['RepoTags'][i]
|
||||
tmp_image['Size'] = tmp_attrs['Size']
|
||||
tmp_image['Labels'] = tmp_attrs['Config']['Labels']
|
||||
tmp_image['Comment'] = tmp_attrs['Comment']
|
||||
tmp_image['Created'] = utc_to_local(
|
||||
tmp_attrs['Created'].split('.')[0])
|
||||
imageList.append(tmp_image)
|
||||
imageList = sorted(imageList, key=lambda x: x['Created'], reverse=True)
|
||||
return imageList
|
||||
|
||||
|
||||
def dockerPull():
|
||||
# pull Dockr 官方镜像
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['images'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
images = args['images']
|
||||
if ':' in images:
|
||||
pass
|
||||
else:
|
||||
images = images + ':latest'
|
||||
|
||||
c = getDClient()
|
||||
try:
|
||||
ret = c.images.pull(images)
|
||||
if ret:
|
||||
return mw.returnJson(True, '拉取成功!')
|
||||
else:
|
||||
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
|
||||
except:
|
||||
ret = mw.execShell('docker image pull %s' % images)
|
||||
if 'invalid' in ret[-1]:
|
||||
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
|
||||
else:
|
||||
return mw.returnJson(True, '拉取成功!')
|
||||
|
||||
|
||||
def dockerPlulPath(path):
|
||||
if not path and path == '':
|
||||
return mw.returnJson(False, 'Invalid address')
|
||||
|
||||
ret = mw.execShell('docker image pull %s' % path)
|
||||
if 'invalid' in ret[-1]:
|
||||
return mw.returnJson(False, '拉取失败,请检查镜像名称或是否需要登录docker进行下载')
|
||||
else:
|
||||
return mw.returnJson(True, '拉取成功!')
|
||||
|
||||
|
||||
def dockerPullReg():
|
||||
# pull Dockr 官方镜像
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = args['path']
|
||||
return dockerPlulPath(path)
|
||||
|
||||
|
||||
# 判断镜像是否存在
|
||||
def checkImage(path):
|
||||
image_list = imageList()
|
||||
for i in image_list:
|
||||
if path == i["RepoTags"]:
|
||||
return mw.returnData(False, '镜像已存在!')
|
||||
|
||||
|
||||
def dockerPullPrivateNew():
|
||||
# pull Dockr 官方镜像
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = args['path']
|
||||
check = checkImage(path)
|
||||
if check:
|
||||
return mw.getJson(check)
|
||||
|
||||
my_repo = repoList()
|
||||
if not my_repo:
|
||||
return mw.returnJson(False, '未登录任何私人存储库,请登录然后拉取')
|
||||
return dockerPlulPath(path)
|
||||
|
||||
|
||||
def imageListData():
|
||||
try:
|
||||
ilist = imageList()
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '未开启Docker')
|
||||
return mw.returnJson(True, 'ok', ilist)
|
||||
|
||||
|
||||
def dockerRemoveImage():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['imageId', 'repoTags'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
repoTags = args['repoTags']
|
||||
imageId = args['imageId']
|
||||
|
||||
c = getDClient()
|
||||
try:
|
||||
c.images.remove(repoTags)
|
||||
return mw.returnJson(True, '成功删除')
|
||||
except:
|
||||
try:
|
||||
c.images.remove(imageId)
|
||||
return mw.returnJson(True, '成功删除!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '删除失败, 当前镜像正在使用!')
|
||||
|
||||
|
||||
def getImageListFunc(dbname=''):
|
||||
bkDir = mw.getRootDir() + '/backup/docker'
|
||||
blist = os.listdir(bkDir)
|
||||
r = []
|
||||
|
||||
bname = 'db_' + dbname
|
||||
blen = len(bname)
|
||||
for x in blist:
|
||||
fbstr = x[0:blen]
|
||||
if fbstr == bname:
|
||||
r.append(x)
|
||||
return r
|
||||
|
||||
|
||||
def dockerImagePickDir():
|
||||
bkDir = mw.getRootDir() + '/backup/docker'
|
||||
return mw.returnJson(True, 'ok', bkDir)
|
||||
|
||||
|
||||
def dockerImagePickList():
|
||||
|
||||
bkDir = mw.getRootDir() + '/backup/docker'
|
||||
if not os.path.exists(bkDir):
|
||||
os.mkdir(bkDir)
|
||||
|
||||
r = os.listdir(bkDir)
|
||||
rr = []
|
||||
for x in range(0, len(r)):
|
||||
p = bkDir + '/' + r[x]
|
||||
data = {}
|
||||
data['name'] = r[x]
|
||||
|
||||
rsize = os.path.getsize(p)
|
||||
data['size'] = mw.toSize(rsize)
|
||||
|
||||
t = os.path.getctime(p)
|
||||
t = time.localtime(t)
|
||||
|
||||
data['time'] = time.strftime('%Y-%m-%d %H:%M:%S', t)
|
||||
rr.append(data)
|
||||
|
||||
data['file'] = p
|
||||
|
||||
return mw.returnJson(True, 'ok', rr)
|
||||
|
||||
|
||||
def dockerImagePickSave():
|
||||
# image 导出
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['images'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
bkDir = mw.getRootDir() + '/backup/docker/'
|
||||
images = args['images']
|
||||
try:
|
||||
file_name = bkDir + \
|
||||
str(time.strftime('%Y%m%d_%H%M%S', time.localtime())) + '.tar.gz'
|
||||
mw.execShell('docker image save %s | gzip > %s' %
|
||||
(images, file_name))
|
||||
return mw.returnJson(True, '导出镜像 {} 成功!'.format(file_name))
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '操作失败: ' + str(ex))
|
||||
|
||||
|
||||
def dockerImagePickLoad():
|
||||
# 镜像文件导入
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
try:
|
||||
file_path = args['file']
|
||||
if not os.path.exists(file_path):
|
||||
return mw.returnJson(False, '文件不存在')
|
||||
if file_path.endswith('.tar'):
|
||||
mw.execShell('docker image load < %s' % file_path)
|
||||
elif file_path.endswith('.tar.gz'):
|
||||
mw.execShell('gunzip -c %s | docker image load' % file_path)
|
||||
else:
|
||||
return mw.returnJson(False, '不支持改文件类型!')
|
||||
return mw.returnJson(True, '导入镜像文件成功!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '操作失败: ' + str(ex))
|
||||
|
||||
|
||||
def dockerLoginCheck(user_name, user_pass, registry):
|
||||
# 登陆验证
|
||||
cmd = 'docker login -u=%s -p %s %s' % (user_name, user_pass, registry)
|
||||
# print(cmd)
|
||||
login_test = mw.execShell(cmd)
|
||||
# print(login_test)
|
||||
ret = 'required$|Error'
|
||||
ret2 = re.findall(ret, login_test[-1])
|
||||
if len(ret2) == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def getDockerIpListData():
|
||||
# 取IP列表
|
||||
path = getServerDir()
|
||||
ipConf = path + '/iplist.json'
|
||||
if not os.path.exists(ipConf):
|
||||
return []
|
||||
iplist = json.loads(mw.readFile(ipConf))
|
||||
return iplist
|
||||
|
||||
|
||||
def getDockerIpList():
|
||||
data = getDockerIpListData()
|
||||
return mw.returnJson(True, 'ok!', data)
|
||||
|
||||
|
||||
def dockerAddIP():
|
||||
# 添加IP
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['address', 'netmask', 'gateway'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = getServerDir()
|
||||
ipConf = path + '/iplist.json'
|
||||
if not os.path.exists(ipConf):
|
||||
iplist = []
|
||||
mw.writeFile(ipConf, json.dumps(iplist))
|
||||
|
||||
iplist = json.loads(mw.readFile(ipConf))
|
||||
ipInfo = {
|
||||
'address': args['address'],
|
||||
'netmask': args['netmask'],
|
||||
'gateway': args['gateway'],
|
||||
}
|
||||
iplist.append(ipInfo)
|
||||
mw.writeFile(ipConf, json.dumps(iplist))
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
|
||||
def dockerDelIP():
|
||||
# 删除IP
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['address'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
path = getServerDir()
|
||||
ipConf = path + '/iplist.json'
|
||||
if not os.path.exists(ipConf):
|
||||
return mw.returnJson(False, '指定的IP不存在。!')
|
||||
iplist = json.loads(mw.readFile(ipConf))
|
||||
newList = []
|
||||
for ipInfo in iplist:
|
||||
if ipInfo['address'] == args['address']:
|
||||
continue
|
||||
newList.append(ipInfo)
|
||||
mw.writeFile(ipConf, json.dumps(newList))
|
||||
return mw.returnJson(True, '成功删除!')
|
||||
|
||||
|
||||
def getDockerCreateInfo():
|
||||
# 取创建依赖
|
||||
import psutil
|
||||
data = {}
|
||||
data['images'] = imageList()
|
||||
data['memSize'] = int(psutil.virtual_memory().total / 1024 / 1024)
|
||||
data['iplist'] = getDockerIpListData()
|
||||
return mw.returnJson(True, 'ok!', data)
|
||||
|
||||
|
||||
def __release_port(port):
|
||||
from collections import namedtuple
|
||||
try:
|
||||
import firewall_api
|
||||
firewall_api.firewall_api().addAcceptPortArgs(port, 'docker', 'port')
|
||||
return port
|
||||
except Exception as e:
|
||||
return "Release failed {}".format(e)
|
||||
|
||||
|
||||
def dockerPortCheck():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['port'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
port = args['port']
|
||||
is_ok = IsPortExists(port)
|
||||
if is_ok:
|
||||
return mw.returnJson(True, 'ok')
|
||||
return mw.returnJson(False, 'fail')
|
||||
|
||||
|
||||
def IsPortExists(port):
|
||||
# 判断端口是否被占用
|
||||
ret = __check_dst_port(ip='localhost', port=port)
|
||||
ret2 = __check_dst_port(ip='0.0.0.0', port=port)
|
||||
if ret:
|
||||
return ret
|
||||
if not ret and ret2:
|
||||
return ret2
|
||||
if not ret and not ret2:
|
||||
return False
|
||||
|
||||
|
||||
def __check_dst_port(ip, port, timeout=3):
|
||||
# 端口检测
|
||||
import socket
|
||||
ok = True
|
||||
try:
|
||||
s = socket.socket()
|
||||
s.settimeout(timeout)
|
||||
s.connect((ip, port))
|
||||
s.close()
|
||||
except:
|
||||
ok = False
|
||||
return ok
|
||||
|
||||
|
||||
def dockerCreateCon():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['environments', 'command',
|
||||
'entrypoint', 'image', 'mem_limit', 'ports', 'volumes'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
environments = args['environments']
|
||||
environments = environments.strip().split()
|
||||
|
||||
command = args['command']
|
||||
entrypoint = args['entrypoint']
|
||||
image = args['image']
|
||||
mem_limit = args['mem_limit']
|
||||
ports = args['ports']
|
||||
ports = ports.replace('[', '(').replace(']', ')')
|
||||
volumes = args['volumes']
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# print(args)
|
||||
try:
|
||||
|
||||
c = getDClient()
|
||||
conObject = c.containers.run(
|
||||
image=image,
|
||||
mem_limit=mem_limit + 'M',
|
||||
ports=eval(ports),
|
||||
auto_remove=False,
|
||||
command=command,
|
||||
detach=True,
|
||||
stdin_open=True,
|
||||
tty=True,
|
||||
entrypoint=entrypoint,
|
||||
privileged=True,
|
||||
volumes=json.loads(volumes),
|
||||
cpu_shares=10,
|
||||
environment=environments
|
||||
)
|
||||
if conObject:
|
||||
__release_port(ports)
|
||||
return mw.returnJson(True, '创建成功!')
|
||||
|
||||
return mw.returnJson(False, '创建失败!')
|
||||
except docker.errors.APIError as ex:
|
||||
return mw.returnJson(False, '创建失败!' + str(ex))
|
||||
|
||||
|
||||
def dockerLogin():
|
||||
args = getArgs()
|
||||
|
||||
# print(args)
|
||||
data = checkArgs(args, ['user', 'passwd', 'hub_name',
|
||||
'namespace', 'registry', 'repository_name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user_name = args['user']
|
||||
user_pass = args['passwd']
|
||||
registry = args['registry']
|
||||
hub_name = args['hub_name']
|
||||
namespace = args['namespace']
|
||||
repository_name = args['repository_name']
|
||||
|
||||
ret_status = dockerLoginCheck(user_name, user_pass, registry)
|
||||
path = getServerDir()
|
||||
if ret_status:
|
||||
user_file = path + '/user.json'
|
||||
user_info = mw.readFile(user_file)
|
||||
if not user_info:
|
||||
user_info = []
|
||||
else:
|
||||
user_info = json.loads(user_info)
|
||||
|
||||
ret = {}
|
||||
ret['user_name'] = user_name
|
||||
ret['user_pass'] = user_pass
|
||||
ret['registry'] = registry
|
||||
ret['hub_name'] = hub_name
|
||||
ret['namespace'] = namespace
|
||||
ret['repository_name'] = repository_name
|
||||
if not registry:
|
||||
ret['registry'] = "docker.io"
|
||||
user_info.append(ret)
|
||||
mw.writeFile(user_file, json.dumps(user_info))
|
||||
return mw.returnJson(True, '成功登录!')
|
||||
return mw.returnJson(False, '登录失败!')
|
||||
|
||||
|
||||
# 删除用户信息
|
||||
def delete_user_info(registry):
|
||||
path = getServerDir()
|
||||
user_file = path + '/user.json'
|
||||
user_info = mw.readFile(user_file)
|
||||
if user_info:
|
||||
user_info = json.loads(user_info)
|
||||
for i in range(len(user_info)):
|
||||
if registry in user_info[i].values():
|
||||
del(user_info[i])
|
||||
mw.writeFile(user_file, json.dumps(user_info))
|
||||
return True
|
||||
|
||||
|
||||
def dockerLogout():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['registry'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
registry = args['registry']
|
||||
if registry == "docker.io":
|
||||
registry = ""
|
||||
login_test = mw.execShell('docker logout %s' % registry)
|
||||
if registry == "":
|
||||
registry = "docker.io"
|
||||
ret = 'required$|Error'
|
||||
ret2 = re.findall(ret, login_test[-1])
|
||||
delete_user_info(registry)
|
||||
if len(ret2) == 0:
|
||||
return mw.returnJson(True, '退出成功')
|
||||
else:
|
||||
return mw.returnJson(True, '退出失败')
|
||||
|
||||
|
||||
def repoList():
|
||||
path = getServerDir()
|
||||
repostory_info = []
|
||||
user_file = path + '/user.json'
|
||||
|
||||
if os.path.exists(user_file):
|
||||
user_info = mw.readFile(user_file)
|
||||
user_info = json.loads(user_info)
|
||||
for i in user_info:
|
||||
tmp = {}
|
||||
tmp["hub_name"] = i["hub_name"]
|
||||
tmp["registry"] = i["registry"]
|
||||
tmp["namespace"] = i["namespace"]
|
||||
tmp['repository_name'] = i["repository_name"]
|
||||
repostory_info.append(tmp)
|
||||
|
||||
return mw.returnJson(True, 'ok', repostory_info)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
elif func == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'con_list':
|
||||
print(conListData())
|
||||
elif func == 'docker_con_log':
|
||||
print(dockerLogCon())
|
||||
elif func == 'docker_remove_con':
|
||||
print(dockerRemoveCon())
|
||||
elif func == 'docker_run_con':
|
||||
print(dockerRunCon())
|
||||
elif func == 'docker_stop_con':
|
||||
print(dockerStopCon())
|
||||
elif func == 'docker_exec':
|
||||
print(dockerExec())
|
||||
elif func == 'docker_pull':
|
||||
print(dockerPull())
|
||||
elif func == 'docker_pull_reg':
|
||||
print(dockerPullReg())
|
||||
elif func == 'image_list':
|
||||
print(imageListData())
|
||||
elif func == 'image_pick_dir':
|
||||
print(dockerImagePickDir())
|
||||
elif func == 'image_pick_save':
|
||||
print(dockerImagePickSave())
|
||||
elif func == 'image_pick_load':
|
||||
print(dockerImagePickLoad())
|
||||
elif func == 'image_pick_list':
|
||||
print(dockerImagePickList())
|
||||
elif func == 'docker_get_iplist':
|
||||
print(getDockerIpList())
|
||||
elif func == 'docker_del_ip':
|
||||
print(dockerDelIP())
|
||||
elif func == 'docker_add_ip':
|
||||
print(dockerAddIP())
|
||||
elif func == 'get_docker_create_info':
|
||||
print(getDockerCreateInfo())
|
||||
elif func == 'docker_create_con':
|
||||
print(dockerCreateCon())
|
||||
elif func == 'docker_remove_image':
|
||||
print(dockerRemoveImage())
|
||||
elif func == 'docker_port_check':
|
||||
print(dockerPortCheck())
|
||||
elif func == 'docker_login':
|
||||
print(dockerLogin())
|
||||
elif func == 'docker_logout':
|
||||
print(dockerLogout())
|
||||
elif func == 'repo_list':
|
||||
print(repoList())
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "Docker是一个开源的应用容器引擎",
|
||||
"name": "docker",
|
||||
"title": "Docker",
|
||||
"shell": "install.sh",
|
||||
"versions":["1.0"],
|
||||
"updates":["1.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/docker",
|
||||
"path": "server/docker",
|
||||
"display": 1,
|
||||
"author": "Zend",
|
||||
"date": "2017-04-01",
|
||||
"home": "https://docker.io",
|
||||
"doc1":"https://docker-py.readthedocs.io/",
|
||||
"type": 0,
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
# cd /www/server/mdserver-web/plugins/docker && /bin/bash install.sh uninstall 1.0
|
||||
# cd /www/server/mdserver-web/plugins/docker && /bin/bash install.sh install 1.0
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
Install_Docker()
|
||||
{
|
||||
# which docker
|
||||
# if [ "$?" == "0" ];then
|
||||
# echo '安装已经完成docker' > $install_tmp
|
||||
# exit 0
|
||||
# fi
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
|
||||
if [ ! -d $serverPath/docker ];then
|
||||
curl -fsSL https://get.docker.com | bash
|
||||
mkdir -p $serverPath/docker
|
||||
fi
|
||||
|
||||
pip install docker
|
||||
pip install pytz
|
||||
|
||||
if [ -d $serverPath/docker ];then
|
||||
echo "${VERSION}" > $serverPath/docker/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/docker/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/docker/index.py initd_install
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_Docker()
|
||||
{
|
||||
CMD=yum
|
||||
which apt
|
||||
if [ "$?" == "0" ];then
|
||||
CMD=apt
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/systemd/system/docker.service ];then
|
||||
systemctl stop docker
|
||||
systemctl disable docker
|
||||
rm -rf /usr/lib/systemd/system/docker.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
$CMD remove -y docker docker-ce-cli containerd.io
|
||||
# docker-client \
|
||||
# docker-client-latest \
|
||||
# docker-common \
|
||||
# docker-latest \
|
||||
# docker-latest-logrotate \
|
||||
# docker-logrotate \
|
||||
# docker-selinux \
|
||||
# docker-engine-selinux \
|
||||
# docker-engine \
|
||||
# docker-ce
|
||||
|
||||
rm -rf $serverPath/docker
|
||||
echo "Uninstall_Docker" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_Docker
|
||||
else
|
||||
Uninstall_Docker
|
||||
fi
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,19 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('dynamic-tracking');">服务</p>
|
||||
<p onclick="pluginInitD('dynamic-tracking');">自启动</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(300);
|
||||
resetPluginWinWidth(500);
|
||||
$.getScript( "/plugins/file?name=dynamic-tracking&f=static/js/dynamic-tracking.js", function(){
|
||||
pluginService('dynamic-tracking', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user