InPanel 1.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inpanel/__init__.py +29 -0
- inpanel/acme.py +289 -0
- inpanel/aliyuncs.py +269 -0
- inpanel/app.py +514 -0
- inpanel/apt.py +223 -0
- inpanel/base.py +200 -0
- inpanel/config.py +139 -0
- inpanel/data/config.ini +29 -0
- inpanel/data/history +5 -0
- inpanel/data/runlogs.ini +12 -0
- inpanel/data/update_info.ini +4 -0
- inpanel/dnf.py +225 -0
- inpanel/lib/__init__.py +9 -0
- inpanel/lib/async_process.py +98 -0
- inpanel/lib/filelock.py +82 -0
- inpanel/lib/magic.py +233 -0
- inpanel/lib/pxssh.py +310 -0
- inpanel/lib/pyDes.py +867 -0
- inpanel/mod/__init__.py +0 -0
- inpanel/mod/apt.py +316 -0
- inpanel/mod/certificate.py +268 -0
- inpanel/mod/config.py +372 -0
- inpanel/mod/cron.py +315 -0
- inpanel/mod/disk.py +322 -0
- inpanel/mod/dnf.py +239 -0
- inpanel/mod/file.py +722 -0
- inpanel/mod/firewall.py +199 -0
- inpanel/mod/firewall_base.py +137 -0
- inpanel/mod/firewall_firewalld.py +170 -0
- inpanel/mod/firewall_iptables.py +176 -0
- inpanel/mod/firewall_macos.py +213 -0
- inpanel/mod/firewall_ufw.py +128 -0
- inpanel/mod/ftp.py +231 -0
- inpanel/mod/httpd.py +1205 -0
- inpanel/mod/lighttpd.py +26 -0
- inpanel/mod/login.py +98 -0
- inpanel/mod/mysql.py +577 -0
- inpanel/mod/named.py +26 -0
- inpanel/mod/nginx.py +2327 -0
- inpanel/mod/package.py +33 -0
- inpanel/mod/package_apt.py +62 -0
- inpanel/mod/package_base.py +77 -0
- inpanel/mod/package_dnf.py +62 -0
- inpanel/mod/package_map.py +366 -0
- inpanel/mod/package_yum.py +64 -0
- inpanel/mod/php.py +289 -0
- inpanel/mod/process.py +291 -0
- inpanel/mod/proftpd.py +26 -0
- inpanel/mod/pureftpd.py +26 -0
- inpanel/mod/query.py +108 -0
- inpanel/mod/server.py +1319 -0
- inpanel/mod/service.py +262 -0
- inpanel/mod/setting.py +228 -0
- inpanel/mod/shell.py +78 -0
- inpanel/mod/ssh.py +280 -0
- inpanel/mod/system.py +220 -0
- inpanel/mod/task.py +1337 -0
- inpanel/mod/ufw.py +14 -0
- inpanel/mod/user.py +306 -0
- inpanel/mod/vsftpd.py +67 -0
- inpanel/mod/yum.py +243 -0
- inpanel/plugins/__init__.py +10 -0
- inpanel/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
- inpanel/plugins/acme/static/index.html +10 -0
- inpanel/plugins/acme/static/index.js +13 -0
- inpanel/plugins/shadowsocks-libev/__pycache__/info.cpython-313.pyc +0 -0
- inpanel/plugins/shadowsocks-libev/info.py +73 -0
- inpanel/plugins/shadowsocks-libev/static/index.html +70 -0
- inpanel/plugins/shadowsocks-libev/static/index.js +18 -0
- inpanel/public/css/global.css +138 -0
- inpanel/public/favicon.ico +0 -0
- inpanel/public/images/alipay.jpg +0 -0
- inpanel/public/images/loading.gif +0 -0
- inpanel/public/images/weixin.jpg +0 -0
- inpanel/public/index.html +94 -0
- inpanel/public/js/controllers/controllers.js +566 -0
- inpanel/public/js/controllers/database.js +590 -0
- inpanel/public/js/controllers/ecs.js +624 -0
- inpanel/public/js/controllers/file.js +940 -0
- inpanel/public/js/controllers/plugins.js +105 -0
- inpanel/public/js/controllers/service.js +1460 -0
- inpanel/public/js/controllers/site.js +1241 -0
- inpanel/public/js/controllers/utils.js +2319 -0
- inpanel/public/js/core.js +221 -0
- inpanel/public/js/directives.js +784 -0
- inpanel/public/js/filters.js +395 -0
- inpanel/public/js/services.js +257 -0
- inpanel/public/lib/angular/1.0.2/angular-resource.min.js +10 -0
- inpanel/public/lib/angular/1.0.2/angular.min.js +158 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css +587 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css +6757 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css.map +1 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- inpanel/public/lib/bootstrap/js/bootstrap.js +2377 -0
- inpanel/public/lib/bootstrap/js/bootstrap.min.js +7 -0
- inpanel/public/lib/bootstrap/js/npm.js +13 -0
- inpanel/public/lib/codemirror/codemirror-compressed.js +1 -0
- inpanel/public/lib/codemirror/codemirror.css +173 -0
- inpanel/public/lib/jquery/jquery-1.12.4.min.js +5 -0
- inpanel/public/lib/md5/md5.js +379 -0
- inpanel/public/lib/md5/md5.min.js +1 -0
- inpanel/public/partials/database/index.html +172 -0
- inpanel/public/partials/database/mysql/dbedit.html +462 -0
- inpanel/public/partials/database/mysql/dbnew.html +348 -0
- inpanel/public/partials/database/mysql/useredit.html +310 -0
- inpanel/public/partials/database/mysql/usernew.html +97 -0
- inpanel/public/partials/directives/message.html +20 -0
- inpanel/public/partials/directives/navbar.html +25 -0
- inpanel/public/partials/directives/selector.html +57 -0
- inpanel/public/partials/directives/srvbase.html +72 -0
- inpanel/public/partials/directives/srvext.html +34 -0
- inpanel/public/partials/directives/srvfile.html +23 -0
- inpanel/public/partials/directives/srvinstall.html +34 -0
- inpanel/public/partials/directives/srvlog.html +23 -0
- inpanel/public/partials/directives/srvminiop.html +28 -0
- inpanel/public/partials/directives/srvuninstall.html +38 -0
- inpanel/public/partials/directives/srvupdate.html +30 -0
- inpanel/public/partials/ecs/account.html +156 -0
- inpanel/public/partials/ecs/ecs.html +198 -0
- inpanel/public/partials/ecs/index.html +40 -0
- inpanel/public/partials/ecs/setings.html +459 -0
- inpanel/public/partials/file/file.html +501 -0
- inpanel/public/partials/file/trash.html +95 -0
- inpanel/public/partials/ftp.html +36 -0
- inpanel/public/partials/log.html +83 -0
- inpanel/public/partials/login.html +79 -0
- inpanel/public/partials/logout.html +22 -0
- inpanel/public/partials/main.html +534 -0
- inpanel/public/partials/plugins/index.html +55 -0
- inpanel/public/partials/plugins/plugins.html +13 -0
- inpanel/public/partials/secure.html +13 -0
- inpanel/public/partials/service/apache.html +147 -0
- inpanel/public/partials/service/cron.html +71 -0
- inpanel/public/partials/service/index.html +293 -0
- inpanel/public/partials/service/iptables.html +40 -0
- inpanel/public/partials/service/lighttpd.html +63 -0
- inpanel/public/partials/service/mariadb.html +113 -0
- inpanel/public/partials/service/memcache.html +36 -0
- inpanel/public/partials/service/minio.html +44 -0
- inpanel/public/partials/service/mongodb.html +44 -0
- inpanel/public/partials/service/mysql.html +113 -0
- inpanel/public/partials/service/named.html +61 -0
- inpanel/public/partials/service/nginx.html +296 -0
- inpanel/public/partials/service/ntp.html +40 -0
- inpanel/public/partials/service/php.html +250 -0
- inpanel/public/partials/service/proftpd.html +59 -0
- inpanel/public/partials/service/pureftpd.html +59 -0
- inpanel/public/partials/service/redis.html +40 -0
- inpanel/public/partials/service/samba.html +58 -0
- inpanel/public/partials/service/sendmail.html +40 -0
- inpanel/public/partials/service/ssh.html +186 -0
- inpanel/public/partials/service/tomcat.html +65 -0
- inpanel/public/partials/service/vsftpd.html +195 -0
- inpanel/public/partials/setting.html +299 -0
- inpanel/public/partials/site/apache/site.html +277 -0
- inpanel/public/partials/site/index.html +344 -0
- inpanel/public/partials/site/nginx/site.html +558 -0
- inpanel/public/partials/sorry.html +19 -0
- inpanel/public/partials/storage/autofm.html +103 -0
- inpanel/public/partials/storage/backup.html +42 -0
- inpanel/public/partials/storage/index.html +360 -0
- inpanel/public/partials/storage/migrate.html +93 -0
- inpanel/public/partials/storage/movedata.html +98 -0
- inpanel/public/partials/storage/remote.html +77 -0
- inpanel/public/partials/utils/cron.html +486 -0
- inpanel/public/partials/utils/firewall.html +266 -0
- inpanel/public/partials/utils/index.html +193 -0
- inpanel/public/partials/utils/network.html +118 -0
- inpanel/public/partials/utils/process.html +239 -0
- inpanel/public/partials/utils/repository.html +373 -0
- inpanel/public/partials/utils/shell.html +28 -0
- inpanel/public/partials/utils/ssl.html +319 -0
- inpanel/public/partials/utils/time.html +109 -0
- inpanel/public/partials/utils/user.html +359 -0
- inpanel/public/robots.txt +2 -0
- inpanel/remote.py +109 -0
- inpanel/templates/file/preview.html +34 -0
- inpanel/templates/index.html +93 -0
- inpanel/utils.py +282 -0
- inpanel/web.py +1811 -0
- inpanel/yum.py +756 -0
- inpanel-1.2.1.dist-info/METADATA +399 -0
- inpanel-1.2.1.dist-info/RECORD +198 -0
- inpanel-1.2.1.dist-info/WHEEL +5 -0
- inpanel-1.2.1.dist-info/entry_points.txt +2 -0
- inpanel-1.2.1.dist-info/licenses/LICENSE +30 -0
- inpanel-1.2.1.dist-info/top_level.txt +1 -0
inpanel/mod/task.py
ADDED
|
@@ -0,0 +1,1337 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2020-2026 Jackson Dou
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# InPanel is distributed under the terms of the (new) BSD License.
|
|
7
|
+
# The full license can be found in 'LICENSE'.
|
|
8
|
+
|
|
9
|
+
"""Module for Task Management."""
|
|
10
|
+
|
|
11
|
+
import time
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from functools import partial
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from shlex import quote
|
|
16
|
+
from subprocess import PIPE, Popen
|
|
17
|
+
|
|
18
|
+
import tornado.escape
|
|
19
|
+
import tornado.httpclient
|
|
20
|
+
|
|
21
|
+
from .. import remote
|
|
22
|
+
from ..base import app_api, os_versint
|
|
23
|
+
from . import disk
|
|
24
|
+
from . import shell
|
|
25
|
+
from . import server
|
|
26
|
+
from . import yum
|
|
27
|
+
from . import mysql
|
|
28
|
+
from . import file
|
|
29
|
+
from . import ssh
|
|
30
|
+
from . import ftp
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TaskManager:
|
|
34
|
+
jobs = {}
|
|
35
|
+
locks = {}
|
|
36
|
+
|
|
37
|
+
def __init__(self, settings, config):
|
|
38
|
+
self.settings = settings
|
|
39
|
+
self.config = config
|
|
40
|
+
|
|
41
|
+
def _lock_job(self, lockname):
|
|
42
|
+
if lockname in self.locks:
|
|
43
|
+
return False
|
|
44
|
+
self.locks[lockname] = True
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
def _unlock_job(self, lockname):
|
|
48
|
+
if lockname not in self.locks:
|
|
49
|
+
return False
|
|
50
|
+
del self.locks[lockname]
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
def _start_job(self, jobname):
|
|
54
|
+
if jobname in self.jobs and self.jobs[jobname]['status'] == 'running':
|
|
55
|
+
return False
|
|
56
|
+
self.jobs[jobname] = {'status': 'running', 'msg': ''}
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
def _update_job(self, jobname, code, msg):
|
|
60
|
+
self.jobs[jobname]['code'] = code
|
|
61
|
+
self.jobs[jobname]['msg'] = msg
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
def _get_job(self, jobname):
|
|
65
|
+
if jobname not in self.jobs:
|
|
66
|
+
return {'status': 'none', 'code': -1, 'msg': ''}
|
|
67
|
+
return self.jobs[jobname]
|
|
68
|
+
|
|
69
|
+
def _finish_job(self, jobname, code, msg, data=None):
|
|
70
|
+
self.jobs[jobname]['status'] = 'finish'
|
|
71
|
+
self.jobs[jobname]['code'] = code
|
|
72
|
+
self.jobs[jobname]['msg'] = msg
|
|
73
|
+
if data:
|
|
74
|
+
self.jobs[jobname]['data'] = data
|
|
75
|
+
|
|
76
|
+
def _call(self, callback):
|
|
77
|
+
tornado.ioloop.IOLoop.instance().add_callback(callback)
|
|
78
|
+
|
|
79
|
+
async def update(self):
|
|
80
|
+
if not self._start_job('update'):
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
root_path = self.settings['root_path']
|
|
84
|
+
data_path = self.settings['data_path']
|
|
85
|
+
|
|
86
|
+
if Path('%s/../.git' % root_path).exists():
|
|
87
|
+
self._finish_job('update', 0, '升级成功!')
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
http_client = tornado.httpclient.AsyncHTTPClient()
|
|
91
|
+
response = await http_client.fetch(app_api['latest'])
|
|
92
|
+
if response.error:
|
|
93
|
+
self._update_job('update', -1, '获取版本信息失败!')
|
|
94
|
+
return
|
|
95
|
+
versioninfo = tornado.escape.json_decode(response.body.decode('utf-8'))
|
|
96
|
+
downloadurl = versioninfo['download']
|
|
97
|
+
initscript = '%s/scripts/init.d/%s/inpanel' % (root_path, self.settings['os_name'])
|
|
98
|
+
binscript = '%s/scripts/bin/inpanel' % root_path
|
|
99
|
+
steps = [
|
|
100
|
+
{
|
|
101
|
+
'desc': '正在备份当前配置文件...',
|
|
102
|
+
'cmd': '/bin/cp -f %s/config.ini /tmp/inpanel_config.ini' % data_path,
|
|
103
|
+
}, {
|
|
104
|
+
'desc': '正在下载安装包...',
|
|
105
|
+
'cmd': 'wget -q "%s" -O %s/inpanel.tar.gz' % (downloadurl, data_path),
|
|
106
|
+
}, {
|
|
107
|
+
'desc': '正在创建解压目录...',
|
|
108
|
+
'cmd': 'mkdir -p %s/inpanel' % data_path,
|
|
109
|
+
}, {
|
|
110
|
+
'desc': '正在解压安装包...',
|
|
111
|
+
'cmd': 'tar zxmf %s/inpanel.tar.gz -C %s/inpanel --strip-components 1' % (data_path, data_path),
|
|
112
|
+
}, {
|
|
113
|
+
'desc': '正在删除旧版本...',
|
|
114
|
+
'cmd': 'find %s -mindepth 1 -maxdepth 1 -path %s -prune -o -exec rm -rf {} \\\\;' % (root_path, data_path),
|
|
115
|
+
}, {
|
|
116
|
+
'desc': '正在复制新版本...',
|
|
117
|
+
'cmd': 'find %s/inpanel -mindepth 1 -maxdepth 1 -exec cp -r {} %s \\\\;' % (data_path, root_path),
|
|
118
|
+
}, {
|
|
119
|
+
'desc': '正在删除旧的服务脚本...',
|
|
120
|
+
'cmd': 'rm -f /etc/init.d/inpanel /usr/bin/inpanel',
|
|
121
|
+
}, {
|
|
122
|
+
'desc': '正在安装新的服务脚本...',
|
|
123
|
+
'cmd': 'ln -s %s /etc/init.d/inpanel' % initscript
|
|
124
|
+
}, {
|
|
125
|
+
'desc': '正在安装新的命令脚本...',
|
|
126
|
+
'cmd': 'ln -s %s /usr/bin/inpanel' % binscript
|
|
127
|
+
}, {
|
|
128
|
+
'desc': '正在更改脚本权限...',
|
|
129
|
+
'cmd': 'chmod +x /usr/bin/inpanel /etc/init.d/inpanel %s/config.py %s/server.py' % (root_path, root_path),
|
|
130
|
+
}, {
|
|
131
|
+
'desc': '正在删除安装临时文件...',
|
|
132
|
+
'cmd': 'rm -rf %s/inpanel %s/inpanel.tar.gz' % (data_path, data_path)
|
|
133
|
+
}, {
|
|
134
|
+
'desc': '正在恢复旧的配置文件...',
|
|
135
|
+
'cmd': '/bin/cp -f /tmp/inpanel_config.ini %s/config.ini' % data_path
|
|
136
|
+
}, {
|
|
137
|
+
'desc': '正在删除旧的配置文件...',
|
|
138
|
+
'cmd': 'rm -f /tmp/inpanel_config.ini'
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
for step in steps:
|
|
142
|
+
desc = step['desc']
|
|
143
|
+
cmd = step['cmd']
|
|
144
|
+
self._update_job('update', 2, desc)
|
|
145
|
+
result, output = await shell.async_command(cmd)
|
|
146
|
+
if result != 0:
|
|
147
|
+
self._update_job('update', -1, desc + '失败!')
|
|
148
|
+
break
|
|
149
|
+
|
|
150
|
+
if result == 0:
|
|
151
|
+
code = 0
|
|
152
|
+
msg = '升级成功!请刷新页面重新登录。'
|
|
153
|
+
else:
|
|
154
|
+
code = -1
|
|
155
|
+
msg = '升级失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
156
|
+
|
|
157
|
+
self._finish_job('update', code, msg)
|
|
158
|
+
|
|
159
|
+
async def service(self, action, service, name):
|
|
160
|
+
jobname = f'service_{action}_{service}'
|
|
161
|
+
if not self._start_job(jobname):
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
action_str = {'start': '启动', 'stop': '停止', 'restart': '重启'}
|
|
165
|
+
self._update_job(jobname, 2, f'正在{action_str[action]} {name} 服务...')
|
|
166
|
+
|
|
167
|
+
if action == 'start' and service in ('sendmail',) and self.settings['os_name'] in ('redhat', 'centos') and os_versint == 5:
|
|
168
|
+
hostname = server.ServerInfo.hostname()
|
|
169
|
+
hostname_found = False
|
|
170
|
+
dot_found = False
|
|
171
|
+
lines = []
|
|
172
|
+
with open('/etc/hosts', encoding='utf-8') as f:
|
|
173
|
+
for line in f:
|
|
174
|
+
if not line.startswith('#') and not hostname_found:
|
|
175
|
+
fields = line.strip().split()
|
|
176
|
+
if hostname in fields:
|
|
177
|
+
hostname_found = True
|
|
178
|
+
dot_found = any(field for field in fields[1:] if '.' in field)
|
|
179
|
+
if not dot_found:
|
|
180
|
+
line = '%s %s.localdomain\n' % (line.strip(), hostname)
|
|
181
|
+
lines.append(line)
|
|
182
|
+
if not dot_found:
|
|
183
|
+
with open('/etc/hosts', 'w', encoding='utf-8') as f:
|
|
184
|
+
f.writelines(lines)
|
|
185
|
+
if os_versint < 7:
|
|
186
|
+
cmd = f'/etc/init.d/{service} {action}'
|
|
187
|
+
else:
|
|
188
|
+
cmd = f'/bin/systemctl {action} {service}.service'
|
|
189
|
+
result, output = await shell.async_command(cmd)
|
|
190
|
+
if result == 0:
|
|
191
|
+
code = 0
|
|
192
|
+
msg = f'{name} 服务{action_str[action]}成功!'
|
|
193
|
+
else:
|
|
194
|
+
code = -1
|
|
195
|
+
txt = output.strip().replace('\n', '<br>')
|
|
196
|
+
msg = f'{name} 服务{action_str[action]}失败!<p style="margin:10px">{txt}</p>'
|
|
197
|
+
|
|
198
|
+
self._finish_job(jobname, code, msg)
|
|
199
|
+
|
|
200
|
+
async def datetime(self, newdatetime):
|
|
201
|
+
jobname = 'datetime'
|
|
202
|
+
if not self._start_job(jobname):
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
self._update_job(jobname, 2, '正在设置系统时间...')
|
|
206
|
+
|
|
207
|
+
cmd = 'date -s %s' % (quote(newdatetime),)
|
|
208
|
+
result, output = await shell.async_command(cmd)
|
|
209
|
+
if result == 0:
|
|
210
|
+
code = 0
|
|
211
|
+
msg = '系统时间设置成功!'
|
|
212
|
+
else:
|
|
213
|
+
code = -1
|
|
214
|
+
txt = output.strip().replace('\n', '<br>')
|
|
215
|
+
msg = f'系统时间设置失败!<p style="margin:10px">{txt}</p>'
|
|
216
|
+
|
|
217
|
+
self._finish_job(jobname, code, msg)
|
|
218
|
+
|
|
219
|
+
async def ntpdate(self, server):
|
|
220
|
+
jobname = 'ntpdate_%s' % server
|
|
221
|
+
if not self._start_job(jobname):
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
self._update_job(jobname, 2, '正在从 %s 同步时间...' % server)
|
|
225
|
+
cmd = 'ntpdate -u %s' % server
|
|
226
|
+
result, output = await shell.async_command(cmd)
|
|
227
|
+
if result == 0:
|
|
228
|
+
code = 0
|
|
229
|
+
offset = output.split(' offset ')[-1].split()[0]
|
|
230
|
+
msg = '同步时间成功!(时间偏差 %s 秒)' % str(offset)
|
|
231
|
+
else:
|
|
232
|
+
code = -1
|
|
233
|
+
if 'no server suitable' in output:
|
|
234
|
+
msg = '同步时间失败!没有找到合适同步服务器。'
|
|
235
|
+
elif 'no servers can be used' in output:
|
|
236
|
+
msg = '同步时间失败!没有找到同步服务器的地址'
|
|
237
|
+
else:
|
|
238
|
+
msg = '同步时间失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
239
|
+
|
|
240
|
+
self._finish_job(jobname, code, msg)
|
|
241
|
+
|
|
242
|
+
async def swapon(self, action, devname):
|
|
243
|
+
jobname = f'swapon_{action}_{devname}'
|
|
244
|
+
if not self._start_job(jobname):
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
action_str = {'on': '启用', 'off': '停用'}
|
|
248
|
+
self._update_job(jobname, 2, f'正在{action_str[action]} {devname}...')
|
|
249
|
+
|
|
250
|
+
if action == 'on':
|
|
251
|
+
cmd = f'swapon /dev/{devname}'
|
|
252
|
+
else:
|
|
253
|
+
cmd = f'swapoff /dev/{devname}'
|
|
254
|
+
|
|
255
|
+
result, output = await shell.async_command(cmd)
|
|
256
|
+
if result == 0:
|
|
257
|
+
code = 0
|
|
258
|
+
msg = f'{action_str[action]} {devname} 成功!'
|
|
259
|
+
else:
|
|
260
|
+
code = -1
|
|
261
|
+
txt = output.strip().replace('\n', '<br>')
|
|
262
|
+
msg = f'{action_str[action]} {devname} 失败!<p style="margin:10px">{txt}</p>'
|
|
263
|
+
|
|
264
|
+
self._finish_job(jobname, code, msg)
|
|
265
|
+
|
|
266
|
+
async def mount(self, action, devname, mountpoint, fstype):
|
|
267
|
+
jobname = 'mount_%s_%s' % (action, devname)
|
|
268
|
+
if not self._start_job(jobname):
|
|
269
|
+
return
|
|
270
|
+
|
|
271
|
+
action_str = {'mount': '挂载', 'umount': '卸载'}
|
|
272
|
+
self._update_job(jobname, 2, '正在%s %s 到 %s...' % (action_str[action], devname, mountpoint))
|
|
273
|
+
|
|
274
|
+
if action == 'mount':
|
|
275
|
+
disk.fstab(devname, {
|
|
276
|
+
'devname': devname,
|
|
277
|
+
'mount': mountpoint,
|
|
278
|
+
'fstype': fstype,
|
|
279
|
+
})
|
|
280
|
+
cmd = 'mount -t %s /dev/%s %s' % (fstype, devname, mountpoint)
|
|
281
|
+
else:
|
|
282
|
+
cmd = 'umount /dev/%s' % (devname)
|
|
283
|
+
|
|
284
|
+
result, output = await shell.async_command(cmd)
|
|
285
|
+
if result == 0:
|
|
286
|
+
code = 0
|
|
287
|
+
msg = '%s %s 成功!' % (action_str[action], devname)
|
|
288
|
+
else:
|
|
289
|
+
code = -1
|
|
290
|
+
msg = '%s %s 失败!<p style="margin:10px">%s</p>' % (action_str[action], devname, output.strip().replace('\n', '<br>'))
|
|
291
|
+
|
|
292
|
+
self._finish_job(jobname, code, msg)
|
|
293
|
+
|
|
294
|
+
async def format(self, devname, fstype):
|
|
295
|
+
jobname = 'format_%s' % devname
|
|
296
|
+
if not self._start_job(jobname):
|
|
297
|
+
return
|
|
298
|
+
|
|
299
|
+
self._update_job(jobname, 2, '正在格式化 %s,可能需要较长时间,请耐心等候...' % devname)
|
|
300
|
+
|
|
301
|
+
if fstype in ('ext2', 'ext3', 'ext4'):
|
|
302
|
+
cmd = 'mkfs.%s -F /dev/%s' % (fstype, devname)
|
|
303
|
+
elif fstype in ('xfs', 'reiserfs', 'btrfs'):
|
|
304
|
+
cmd = 'mkfs.%s -f /dev/%s' % (fstype, devname)
|
|
305
|
+
elif fstype == 'swap':
|
|
306
|
+
cmd = 'mkswap -f /dev/%s' % devname
|
|
307
|
+
else:
|
|
308
|
+
cmd = 'mkfs.%s /dev/%s' % (fstype, devname)
|
|
309
|
+
result, output = await shell.async_command(cmd)
|
|
310
|
+
if result == 0:
|
|
311
|
+
code = 0
|
|
312
|
+
msg = '%s 格式化成功!' % devname
|
|
313
|
+
else:
|
|
314
|
+
code = -1
|
|
315
|
+
msg = '%s 格式化失败!<p style="margin:10px">%s</p>' % (devname, output.strip().replace('\n', '<br>'))
|
|
316
|
+
|
|
317
|
+
self._finish_job(jobname, code, msg)
|
|
318
|
+
|
|
319
|
+
async def yum_repolist(self):
|
|
320
|
+
jobname = 'yum_repolist'
|
|
321
|
+
if not self._start_job(jobname):
|
|
322
|
+
return
|
|
323
|
+
if not self._lock_job('yum'):
|
|
324
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,读取软件源列表失败。')
|
|
325
|
+
return
|
|
326
|
+
|
|
327
|
+
self._update_job(jobname, 2, '正在获取软件源列表...')
|
|
328
|
+
|
|
329
|
+
cmd = 'yum repolist --disableplugin=fastestmirror'
|
|
330
|
+
result, output = await shell.async_command(cmd)
|
|
331
|
+
data = []
|
|
332
|
+
if result == 0:
|
|
333
|
+
code = 0
|
|
334
|
+
msg = '获取软件源列表成功!'
|
|
335
|
+
lines = output.split('\n')
|
|
336
|
+
for line in lines:
|
|
337
|
+
if not line:
|
|
338
|
+
continue
|
|
339
|
+
repo = line.split()[0]
|
|
340
|
+
if repo in yum.yum_repolist:
|
|
341
|
+
data.append(repo)
|
|
342
|
+
else:
|
|
343
|
+
code = -1
|
|
344
|
+
msg = '获取软件源列表失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
345
|
+
|
|
346
|
+
self._finish_job(jobname, code, msg, data)
|
|
347
|
+
self._unlock_job('yum')
|
|
348
|
+
|
|
349
|
+
async def yum_installrepo(self, repo):
|
|
350
|
+
jobname = 'yum_installrepo_%s' % repo
|
|
351
|
+
if not self._start_job(jobname):
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
if repo not in yum.yum_repolist:
|
|
355
|
+
self._finish_job(jobname, -1, '不可识别的软件源!')
|
|
356
|
+
self._unlock_job('yum')
|
|
357
|
+
return
|
|
358
|
+
|
|
359
|
+
self._update_job(jobname, 2, '正在安装软件源 %s...' % repo)
|
|
360
|
+
|
|
361
|
+
arch = self.settings['arch']
|
|
362
|
+
|
|
363
|
+
cmds = []
|
|
364
|
+
if repo == 'base':
|
|
365
|
+
for cmd in yum.get_repo_release(os_versint, self.settings['os_name'], self.settings['arch']):
|
|
366
|
+
cmds.append(cmd)
|
|
367
|
+
|
|
368
|
+
elif repo in ('epel', 'CentALT'):
|
|
369
|
+
for cmd in yum.get_repo_epel(os_versint, self.settings['os_name'], self.settings['arch']):
|
|
370
|
+
cmds.append(cmd)
|
|
371
|
+
|
|
372
|
+
elif repo == 'ius':
|
|
373
|
+
result, output = await shell.async_command(yum.yum_repoinstallcmds['ius'])
|
|
374
|
+
if result != 0:
|
|
375
|
+
error = True
|
|
376
|
+
|
|
377
|
+
elif repo == '10gen':
|
|
378
|
+
with open('/etc/yum.repos.d/10gen.repo', 'w', encoding='utf-8') as f:
|
|
379
|
+
f.write(yum.yum_repostr['10gen'][self.settings['arch']])
|
|
380
|
+
|
|
381
|
+
elif repo == 'mariadb':
|
|
382
|
+
with open('/etc/yum.repos.d/mariadb.repo', 'w', encoding='utf-8') as f:
|
|
383
|
+
f.write(yum.yum_repostr['mariadb'][self.settings['arch']])
|
|
384
|
+
|
|
385
|
+
elif repo == 'atomic':
|
|
386
|
+
result, output = await shell.async_command(yum.yum_repoinstallcmds['atomic'])
|
|
387
|
+
if result != 0:
|
|
388
|
+
error = True
|
|
389
|
+
|
|
390
|
+
error = False
|
|
391
|
+
for cmd in cmds:
|
|
392
|
+
result, output = await shell.async_command(cmd)
|
|
393
|
+
if result != 0 and not 'already installed' in output:
|
|
394
|
+
error = True
|
|
395
|
+
break
|
|
396
|
+
|
|
397
|
+
if repo == 'CentALT':
|
|
398
|
+
repofile = '/etc/yum.repos.d/centalt.repo'
|
|
399
|
+
if Path(repofile).is_file():
|
|
400
|
+
lines = []
|
|
401
|
+
baseurl_found = False
|
|
402
|
+
with open(repofile, encoding='utf-8') as f:
|
|
403
|
+
for line in f:
|
|
404
|
+
if line.startswith('baseurl='):
|
|
405
|
+
baseurl_found = True
|
|
406
|
+
line = '#%s' % line
|
|
407
|
+
lines.append(line)
|
|
408
|
+
lines.append(line)
|
|
409
|
+
if baseurl_found:
|
|
410
|
+
with open(repofile, 'w', encoding='utf-8') as f:
|
|
411
|
+
f.writelines(lines)
|
|
412
|
+
|
|
413
|
+
if not error:
|
|
414
|
+
code = 0
|
|
415
|
+
msg = '软件源 %s 安装成功!' % repo
|
|
416
|
+
else:
|
|
417
|
+
code = -1
|
|
418
|
+
msg = '软件源 %s 安装失败!<p style="margin:10px">%s</p>' % (repo, output.strip().replace('\n', '<br>'))
|
|
419
|
+
|
|
420
|
+
self._finish_job(jobname, code, msg)
|
|
421
|
+
|
|
422
|
+
async def yum_info(self, pkg, repo, option):
|
|
423
|
+
jobname = 'yum_info_%s' % pkg
|
|
424
|
+
if not self._start_job(jobname):
|
|
425
|
+
return
|
|
426
|
+
if not self._lock_job('yum'):
|
|
427
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,读取软件包信息失败。')
|
|
428
|
+
return
|
|
429
|
+
|
|
430
|
+
self._update_job(jobname, 2, '正在获取软件版本信息...')
|
|
431
|
+
|
|
432
|
+
if repo == '*':
|
|
433
|
+
repo = ''
|
|
434
|
+
arch = self.settings['arch']
|
|
435
|
+
if pkg in yum.yum_pkg_noarchitecture:
|
|
436
|
+
arch = 'noarch'
|
|
437
|
+
if option == 'install':
|
|
438
|
+
cmds = ['yum info %s %s.%s --showduplicates --disableplugin=fastestmirror'
|
|
439
|
+
% (repo, alias, arch) for alias in yum.yum_pkg_alias[pkg]]
|
|
440
|
+
else:
|
|
441
|
+
cmds = ['yum info %s.%s --disableplugin=fastestmirror' % (pkg, arch)]
|
|
442
|
+
|
|
443
|
+
data = []
|
|
444
|
+
matched = False
|
|
445
|
+
await shell.async_command('LANG="en_US.UTF-8"')
|
|
446
|
+
for cmd in cmds:
|
|
447
|
+
result, output = await shell.async_command(cmd)
|
|
448
|
+
if result == 0:
|
|
449
|
+
matched = True
|
|
450
|
+
lines = output.split('\n')
|
|
451
|
+
for line in lines:
|
|
452
|
+
if any(line.startswith(word)
|
|
453
|
+
for word in ('Name', 'Version', 'Release', 'Size', 'Repo', 'From repo', 'Summary', 'URL', 'License')):
|
|
454
|
+
fields = line.strip().split(':', 1)
|
|
455
|
+
if len(fields) != 2:
|
|
456
|
+
continue
|
|
457
|
+
field_name = fields[0].strip().lower().replace(' ', '_')
|
|
458
|
+
field_value = fields[1].strip()
|
|
459
|
+
if field_name == 'name':
|
|
460
|
+
data.append({})
|
|
461
|
+
if field_name == 'repo':
|
|
462
|
+
data[-1][field_name] = field_value.split('/')[0]
|
|
463
|
+
else:
|
|
464
|
+
data[-1][field_name] = field_value
|
|
465
|
+
|
|
466
|
+
if matched:
|
|
467
|
+
code = 0
|
|
468
|
+
msg = '获取软件版本信息成功!'
|
|
469
|
+
data = [pkg for pkg in data if pkg['repo'] in yum.yum_repolist + ('installed',)]
|
|
470
|
+
if option == 'update' and len(data) == 1:
|
|
471
|
+
msg = '没有找到可用的新版本!'
|
|
472
|
+
else:
|
|
473
|
+
code = -1
|
|
474
|
+
msg = '获取软件版本信息失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
475
|
+
|
|
476
|
+
self._finish_job(jobname, code, msg, data)
|
|
477
|
+
self._unlock_job('yum')
|
|
478
|
+
|
|
479
|
+
async def yum_install(self, repo, pkg, version, release, ext):
|
|
480
|
+
jobname = 'yum_install_%s_%s_%s_%s_%s' % (repo, pkg, ext, version, release)
|
|
481
|
+
jobname = jobname.strip('_').replace('__', '_')
|
|
482
|
+
if not self._start_job(jobname):
|
|
483
|
+
return
|
|
484
|
+
if not self._lock_job('yum'):
|
|
485
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,安装失败。')
|
|
486
|
+
return
|
|
487
|
+
|
|
488
|
+
if ext:
|
|
489
|
+
self._update_job(jobname, 2, '正在下载并安装扩展包,请耐心等候...')
|
|
490
|
+
else:
|
|
491
|
+
self._update_job(jobname, 2, '正在下载并安装软件包,请耐心等候...')
|
|
492
|
+
|
|
493
|
+
arch = self.settings['arch']
|
|
494
|
+
if pkg in yum.yum_pkg_noarchitecture:
|
|
495
|
+
arch = 'noarch'
|
|
496
|
+
|
|
497
|
+
if ext:
|
|
498
|
+
if version:
|
|
499
|
+
if release:
|
|
500
|
+
pkgs = ['%s-%s-%s.%s' % (ext, version, release, arch)]
|
|
501
|
+
else:
|
|
502
|
+
pkgs = ['%s-%s.%s' % (ext, version, arch)]
|
|
503
|
+
else:
|
|
504
|
+
pkgs = ['%s.%s' % (ext, arch)]
|
|
505
|
+
else:
|
|
506
|
+
if version:
|
|
507
|
+
if release:
|
|
508
|
+
pkgs = ['%s-%s-%s.%s' % (p, version, release, arch)
|
|
509
|
+
for p, pinfo in yum.yum_pkg_relatives[pkg].items() if pinfo['default']]
|
|
510
|
+
else:
|
|
511
|
+
pkgs = ['%s-%s.%s' % (p, version, arch)
|
|
512
|
+
for p, pinfo in yum.yum_pkg_relatives[pkg].items() if pinfo['default']]
|
|
513
|
+
else:
|
|
514
|
+
pkgs = ['%s.%s' % (p, arch)
|
|
515
|
+
for p, pinfo in yum.yum_pkg_relatives[pkg].items() if pinfo['default']]
|
|
516
|
+
repos = [repo, ]
|
|
517
|
+
if repo in ('CentALT', 'ius', 'atomic', '10gen', 'mariadb'):
|
|
518
|
+
repos.extend(['base', 'updates', 'epel'])
|
|
519
|
+
exclude_repos = [r for r in yum.yum_repolist if r not in repos]
|
|
520
|
+
|
|
521
|
+
endinstall = False
|
|
522
|
+
hasconflict = False
|
|
523
|
+
conflicts_backups = []
|
|
524
|
+
while not endinstall:
|
|
525
|
+
cmd = 'yum install -y %s --disablerepo=%s' % (' '.join(pkgs), ','.join(exclude_repos))
|
|
526
|
+
result, output = await shell.async_command(cmd)
|
|
527
|
+
pkg_ext = ext and ext or pkg
|
|
528
|
+
|
|
529
|
+
pkgstr = version and '%s v%s-%s' % (pkg_ext, version, release) or (pkg_ext)
|
|
530
|
+
if result == 0:
|
|
531
|
+
if hasconflict:
|
|
532
|
+
cmd = 'yum install -y %s' % (' '.join(conflicts_backups),)
|
|
533
|
+
result, output = await shell.async_command(cmd)
|
|
534
|
+
endinstall = True
|
|
535
|
+
code = 0
|
|
536
|
+
msg = '%s 安装成功!' % pkgstr
|
|
537
|
+
else:
|
|
538
|
+
clines = output.split('\n')
|
|
539
|
+
for cline in clines:
|
|
540
|
+
if cline.startswith('Error:') and ' conflicts with ' in cline:
|
|
541
|
+
hasconflict = True
|
|
542
|
+
conflict_pkg = cline.split(' conflicts with ', 1)[1]
|
|
543
|
+
self._update_job(jobname, 2, '检测到软件冲突,正在卸载处理冲突...')
|
|
544
|
+
tcmd = 'yum erase -y %s' % conflict_pkg
|
|
545
|
+
result, output = await shell.async_command(tcmd)
|
|
546
|
+
if result == 0:
|
|
547
|
+
lines = output.split('\n')
|
|
548
|
+
conflicts_backups = []
|
|
549
|
+
linestart = False
|
|
550
|
+
for line in lines:
|
|
551
|
+
if not linestart:
|
|
552
|
+
if not line.startswith('Removing for dependencies:'):
|
|
553
|
+
continue
|
|
554
|
+
linestart = True
|
|
555
|
+
if not line.strip():
|
|
556
|
+
break
|
|
557
|
+
fields = line.split()
|
|
558
|
+
conflicts_backups.append('%s-%s' % (fields[0], fields[2]))
|
|
559
|
+
else:
|
|
560
|
+
endinstall = True
|
|
561
|
+
break
|
|
562
|
+
elif 'conflicts between' in cline:
|
|
563
|
+
pass
|
|
564
|
+
if not hasconflict:
|
|
565
|
+
endinstall = True
|
|
566
|
+
if endinstall:
|
|
567
|
+
code = -1
|
|
568
|
+
msg = '%s 安装失败!<p style="margin:10px">%s</p>' % (pkgstr, output.strip().replace('\n', '<br>'))
|
|
569
|
+
|
|
570
|
+
self._finish_job(jobname, code, msg)
|
|
571
|
+
self._unlock_job('yum')
|
|
572
|
+
|
|
573
|
+
async def yum_uninstall(self, repo, pkg, version, release, ext):
|
|
574
|
+
jobname = 'yum_uninstall_%s_%s_%s_%s' % (pkg, ext, version, release)
|
|
575
|
+
jobname = jobname.strip('_').replace('__', '_')
|
|
576
|
+
if not self._start_job(jobname):
|
|
577
|
+
return
|
|
578
|
+
if not self._lock_job('yum'):
|
|
579
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,卸载失败。')
|
|
580
|
+
return
|
|
581
|
+
|
|
582
|
+
if ext:
|
|
583
|
+
self._update_job(jobname, 2, '正在卸载扩展包...')
|
|
584
|
+
else:
|
|
585
|
+
self._update_job(jobname, 2, '正在卸载软件包...')
|
|
586
|
+
|
|
587
|
+
arch = self.settings['arch']
|
|
588
|
+
if pkg in yum.yum_pkg_noarchitecture:
|
|
589
|
+
arch = 'noarch'
|
|
590
|
+
|
|
591
|
+
if ext:
|
|
592
|
+
pkgs = ['%s-%s-%s.%s' % (ext, version, release, arch)]
|
|
593
|
+
else:
|
|
594
|
+
pkgs = ['%s-%s-%s.%s' % (p, version, release, arch)
|
|
595
|
+
for p, pinfo in yum.yum_pkg_relatives[pkg].items()
|
|
596
|
+
if 'base' in pinfo and pinfo['base']]
|
|
597
|
+
cmd = 'yum erase -y %s' % (' '.join(pkgs),)
|
|
598
|
+
result, output = await shell.async_command(cmd)
|
|
599
|
+
pkg_ext = ext and ext or pkg
|
|
600
|
+
if result == 0:
|
|
601
|
+
code = 0
|
|
602
|
+
msg = '%s v%s-%s 卸载成功!' % (pkg_ext, version, release)
|
|
603
|
+
else:
|
|
604
|
+
code = -1
|
|
605
|
+
msg = '%s v%s-%s 卸载失败!<p style="margin:10px">%s</p>' % \
|
|
606
|
+
(pkg_ext, version, release, output.strip().replace('\n', '<br>'))
|
|
607
|
+
|
|
608
|
+
self._finish_job(jobname, code, msg)
|
|
609
|
+
self._unlock_job('yum')
|
|
610
|
+
|
|
611
|
+
async def yum_update(self, repo, pkg, version, release, ext):
|
|
612
|
+
jobname = 'yum_update_%s_%s_%s_%s_%s' % (repo, pkg, ext, version, release)
|
|
613
|
+
jobname = jobname.strip('_').replace('__', '_')
|
|
614
|
+
if not self._start_job(jobname):
|
|
615
|
+
return
|
|
616
|
+
if not self._lock_job('yum'):
|
|
617
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,更新失败。')
|
|
618
|
+
return
|
|
619
|
+
|
|
620
|
+
if ext:
|
|
621
|
+
self._update_job(jobname, 2, '正在下载并升级扩展包,请耐心等候...')
|
|
622
|
+
else:
|
|
623
|
+
self._update_job(jobname, 2, '正在下载并升级软件包,请耐心等候...')
|
|
624
|
+
|
|
625
|
+
pkg_ext = ext and ext or pkg
|
|
626
|
+
|
|
627
|
+
arch = self.settings['arch']
|
|
628
|
+
if pkg_ext in yum.yum_pkg_noarchitecture:
|
|
629
|
+
arch = 'noarch'
|
|
630
|
+
|
|
631
|
+
cmd = 'yum update -y %s-%s-%s.%s' % (pkg_ext, version, release, arch)
|
|
632
|
+
result, output = await shell.async_command(cmd)
|
|
633
|
+
if result == 0:
|
|
634
|
+
code = 0
|
|
635
|
+
msg = '成功升级 %s 到版本 v%s-%s!' % (pkg_ext, version, release)
|
|
636
|
+
else:
|
|
637
|
+
code = -1
|
|
638
|
+
msg = '%s 升级到版本 v%s-%s 失败!<p style="margin:10px">%s</p>' % \
|
|
639
|
+
(pkg_ext, version, release, output.strip().replace('\n', '<br>'))
|
|
640
|
+
|
|
641
|
+
self._finish_job(jobname, code, msg)
|
|
642
|
+
self._unlock_job('yum')
|
|
643
|
+
|
|
644
|
+
async def yum_ext_info(self, pkg):
|
|
645
|
+
jobname = 'yum_ext_info_%s' % pkg
|
|
646
|
+
if not self._start_job(jobname):
|
|
647
|
+
return
|
|
648
|
+
if not self._lock_job('yum'):
|
|
649
|
+
self._finish_job(jobname, -1, '已有一个YUM进程在运行,获取扩展信息失败。')
|
|
650
|
+
return
|
|
651
|
+
|
|
652
|
+
self._update_job(jobname, 2, '正在收集扩展信息...')
|
|
653
|
+
|
|
654
|
+
exts = [k for k, v in yum.yum_pkg_relatives[pkg].items() if 'isext' in v and v['isext']]
|
|
655
|
+
cmd = 'yum info %s --disableplugin=fastestmirror' % (' '.join(['%s.%s' % (ext, self.settings['arch']) for ext in exts]))
|
|
656
|
+
|
|
657
|
+
data = []
|
|
658
|
+
matched = False
|
|
659
|
+
await shell.async_command('LANG="en_US.UTF-8"')
|
|
660
|
+
result, output = await shell.async_command(cmd)
|
|
661
|
+
if result == 0:
|
|
662
|
+
matched = True
|
|
663
|
+
lines = output.split('\n')
|
|
664
|
+
for line in lines:
|
|
665
|
+
if any(line.startswith(word)
|
|
666
|
+
for word in ('Name', 'Version', 'Release', 'Size',
|
|
667
|
+
'Repo', 'From repo')):
|
|
668
|
+
fields = line.strip().split(':', 1)
|
|
669
|
+
if len(fields) != 2:
|
|
670
|
+
continue
|
|
671
|
+
field_name = fields[0].strip().lower().replace(' ', '_')
|
|
672
|
+
field_value = fields[1].strip()
|
|
673
|
+
if field_name == 'name':
|
|
674
|
+
data.append({})
|
|
675
|
+
data[-1][field_name] = field_value
|
|
676
|
+
if matched:
|
|
677
|
+
code = 0
|
|
678
|
+
msg = '获取扩展信息成功!'
|
|
679
|
+
else:
|
|
680
|
+
code = -1
|
|
681
|
+
msg = '获取扩展信息失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
682
|
+
|
|
683
|
+
self._finish_job(jobname, code, msg, data)
|
|
684
|
+
self._unlock_job('yum')
|
|
685
|
+
|
|
686
|
+
async def copy(self, srcpath, despath):
|
|
687
|
+
jobname = 'copy_%s_%s' % (srcpath, despath)
|
|
688
|
+
|
|
689
|
+
if not self._start_job(jobname):
|
|
690
|
+
return
|
|
691
|
+
|
|
692
|
+
self._update_job(jobname, 2, '正在复制 %s 到 %s...' % (srcpath, despath))
|
|
693
|
+
|
|
694
|
+
cmd = 'cp -rf %s %s' % (quote(srcpath), quote(despath))
|
|
695
|
+
result, output = await shell.async_command(cmd)
|
|
696
|
+
|
|
697
|
+
if result == 0:
|
|
698
|
+
code = 0
|
|
699
|
+
msg = '复制 %s 到 %s 完成!' % (srcpath, despath)
|
|
700
|
+
else:
|
|
701
|
+
code = -1
|
|
702
|
+
msg = '复制 %s 到 %s 失败!<p style="margin:10px">%s</p>' % (srcpath, despath, output.strip().replace('\n', '<br>'))
|
|
703
|
+
|
|
704
|
+
self._finish_job(jobname, code, msg)
|
|
705
|
+
|
|
706
|
+
async def move(self, srcpath, despath):
|
|
707
|
+
jobname = 'move_%s_%s' % (srcpath, despath)
|
|
708
|
+
if not self._start_job(jobname):
|
|
709
|
+
return
|
|
710
|
+
|
|
711
|
+
self._update_job(jobname, 2, '正在移动 %s 到 %s...' % (srcpath, despath))
|
|
712
|
+
|
|
713
|
+
despath_exists = Path(despath).exists()
|
|
714
|
+
|
|
715
|
+
if despath_exists:
|
|
716
|
+
if not Path(srcpath).exists():
|
|
717
|
+
self._finish_job(jobname, -1, '不可识别的源!')
|
|
718
|
+
return
|
|
719
|
+
cmd = 'cp -rf %s/* %s' % (quote(srcpath), quote(despath))
|
|
720
|
+
else:
|
|
721
|
+
cmd = 'mv %s %s' % (quote(srcpath), quote(despath))
|
|
722
|
+
result, output = await shell.async_command(cmd)
|
|
723
|
+
if result == 0:
|
|
724
|
+
code = 0
|
|
725
|
+
msg = '移动 %s 到 %s 完成!' % (srcpath, despath)
|
|
726
|
+
else:
|
|
727
|
+
code = -1
|
|
728
|
+
msg = '移动 %s 到 %s 失败!<p style="margin:10px">%s</p>' % (srcpath, despath, output.strip().replace('\n', '<br>'))
|
|
729
|
+
|
|
730
|
+
if despath_exists and code == 0:
|
|
731
|
+
cmd = 'rm -rf %s' % (quote(srcpath),)
|
|
732
|
+
result, output = await shell.async_command(cmd)
|
|
733
|
+
if result == 0:
|
|
734
|
+
code = 0
|
|
735
|
+
msg = '移动 %s 到 %s 完成!' % (srcpath, despath)
|
|
736
|
+
else:
|
|
737
|
+
code = -1
|
|
738
|
+
msg = '移动 %s 到 %s 失败!<p style="margin:10px">%s</p>' % (srcpath, despath, output.strip().replace('\n', '<br>'))
|
|
739
|
+
|
|
740
|
+
self._finish_job(jobname, code, msg)
|
|
741
|
+
|
|
742
|
+
async def remove(self, paths):
|
|
743
|
+
jobname = 'remove_%s' % ','.join(paths)
|
|
744
|
+
if not self._start_job(jobname):
|
|
745
|
+
return
|
|
746
|
+
|
|
747
|
+
for path in paths:
|
|
748
|
+
self._update_job(jobname, 2, '正在删除 %s...' % path)
|
|
749
|
+
cmd = 'rm -rf %s' % (quote(path))
|
|
750
|
+
result, output = await shell.async_command(cmd)
|
|
751
|
+
|
|
752
|
+
if result == 0:
|
|
753
|
+
code = 0
|
|
754
|
+
msg = '删除 %s 成功!' % path
|
|
755
|
+
else:
|
|
756
|
+
code = -1
|
|
757
|
+
msg = '删除 %s 失败!<p style="margin:10px">%s</p>' % (path, output.strip().replace('\n', '<br>'))
|
|
758
|
+
|
|
759
|
+
self._finish_job(jobname, code, msg)
|
|
760
|
+
|
|
761
|
+
async def compress(self, zippath, paths):
|
|
762
|
+
jobname = 'compress_%s_%s' % (zippath, ','.join(paths))
|
|
763
|
+
if not self._start_job(jobname):
|
|
764
|
+
return
|
|
765
|
+
self._update_job(jobname, 2, '正在压缩生成 %s...' % zippath)
|
|
766
|
+
|
|
767
|
+
basepath = str(Path(zippath).parent) + '/'
|
|
768
|
+
path = ' '.join([quote(item.replace(basepath, '')) for item in paths])
|
|
769
|
+
if zippath.endswith('.tar.gz') or zippath.endswith('.tgz'):
|
|
770
|
+
cmd = 'tar zcf %s -C %s %s' % (quote(zippath), quote(basepath), path)
|
|
771
|
+
elif zippath.endswith('.tar.bz2'):
|
|
772
|
+
cmd = 'tar jcf %s -C %s %s' % (quote(zippath), quote(basepath), path)
|
|
773
|
+
elif zippath.endswith('.zip'):
|
|
774
|
+
if not Path('/usr/bin/zip').exists():
|
|
775
|
+
self._update_job(jobname, 2, '正在安装 zip...')
|
|
776
|
+
if self.settings['os_name'] in ('centos', 'redhat'):
|
|
777
|
+
cmd = 'yum install -y zip unzip'
|
|
778
|
+
result, output = await shell.async_command(cmd)
|
|
779
|
+
if result == 0:
|
|
780
|
+
self._update_job(jobname, 0, 'zip 安装成功!')
|
|
781
|
+
else:
|
|
782
|
+
self._update_job(jobname, -1, 'zip 安装失败!')
|
|
783
|
+
return
|
|
784
|
+
cmd = 'cd %s; zip -rq9 %s %s' % (quote(basepath), quote(zippath), path)
|
|
785
|
+
elif zippath.endswith('.gz'):
|
|
786
|
+
path = ' '.join([quote(item) for item in paths])
|
|
787
|
+
cmd = 'gzip -f %s' % path
|
|
788
|
+
else:
|
|
789
|
+
self._finish_job(jobname, -1, '不支持的类型!')
|
|
790
|
+
return
|
|
791
|
+
|
|
792
|
+
result, output = await shell.async_command(cmd)
|
|
793
|
+
if result == 0:
|
|
794
|
+
code = 0
|
|
795
|
+
msg = '压缩到 %s 成功!' % zippath
|
|
796
|
+
else:
|
|
797
|
+
code = -1
|
|
798
|
+
msg = '压缩失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
799
|
+
|
|
800
|
+
self._finish_job(jobname, code, msg)
|
|
801
|
+
|
|
802
|
+
async def decompress(self, zippath, despath):
|
|
803
|
+
jobname = 'decompress_%s_%s' % (zippath, despath)
|
|
804
|
+
if not self._start_job(jobname):
|
|
805
|
+
return
|
|
806
|
+
|
|
807
|
+
self._update_job(jobname, 2, '正在解压 %s...' % zippath)
|
|
808
|
+
if zippath.endswith('.tar.gz') or zippath.endswith('.tgz'):
|
|
809
|
+
cmd = 'tar zxf %s -C %s' % (quote(zippath), quote(despath))
|
|
810
|
+
elif zippath.endswith('.tar.bz2'):
|
|
811
|
+
cmd = 'tar jxf %s -C %s' % (quote(zippath), quote(despath))
|
|
812
|
+
elif zippath.endswith('.zip'):
|
|
813
|
+
if not Path('/usr/bin/unzip').is_file():
|
|
814
|
+
self._update_job(jobname, 2, '正在安装 unzip...')
|
|
815
|
+
if self.settings['os_name'] in ('centos', 'redhat'):
|
|
816
|
+
cmd = 'yum install -y zip unzip'
|
|
817
|
+
result, output = await shell.async_command(cmd)
|
|
818
|
+
if result == 0:
|
|
819
|
+
self._update_job(jobname, 0, 'unzip 安装成功!')
|
|
820
|
+
else:
|
|
821
|
+
self._update_job(jobname, -1, 'unzip 安装失败!')
|
|
822
|
+
return
|
|
823
|
+
cmd = 'unzip -q -o %s -d %s' % (quote(zippath), quote(despath))
|
|
824
|
+
elif zippath.endswith('.gz'):
|
|
825
|
+
cmd = 'gunzip -f %s' % quote(zippath)
|
|
826
|
+
else:
|
|
827
|
+
self._finish_job(jobname, -1, '不支持的类型!')
|
|
828
|
+
return
|
|
829
|
+
|
|
830
|
+
result, output = await shell.async_command(cmd)
|
|
831
|
+
if result == 0:
|
|
832
|
+
code = 0
|
|
833
|
+
msg = '解压 %s 成功!' % zippath
|
|
834
|
+
else:
|
|
835
|
+
code = -1
|
|
836
|
+
msg = '解压 %s 失败!<p style="margin:10px">%s</p>' % (zippath, output.strip().replace('\n', '<br>'))
|
|
837
|
+
|
|
838
|
+
self._finish_job(jobname, code, msg)
|
|
839
|
+
|
|
840
|
+
async def chown(self, paths, user, group, option):
|
|
841
|
+
jobname = 'chown_%s' % ','.join(paths)
|
|
842
|
+
if not self._start_job(jobname):
|
|
843
|
+
return
|
|
844
|
+
|
|
845
|
+
self._update_job(jobname, 2, '正在设置用户和用户组...')
|
|
846
|
+
|
|
847
|
+
for path in paths:
|
|
848
|
+
result = await shell.async_task(file.chown, path, user, group, option == '-R')
|
|
849
|
+
if result == True:
|
|
850
|
+
code = 0
|
|
851
|
+
msg = '设置用户和用户组成功!'
|
|
852
|
+
else:
|
|
853
|
+
code = -1
|
|
854
|
+
msg = '设置 %s 的用户和用户组时失败!' % path
|
|
855
|
+
break
|
|
856
|
+
|
|
857
|
+
self._finish_job(jobname, code, msg)
|
|
858
|
+
|
|
859
|
+
async def chmod(self, paths, perms, option):
|
|
860
|
+
jobname = 'chmod_%s' % ','.join(paths)
|
|
861
|
+
if not self._start_job(jobname):
|
|
862
|
+
return
|
|
863
|
+
|
|
864
|
+
self._update_job(jobname, 2, '正在设置权限...')
|
|
865
|
+
|
|
866
|
+
try:
|
|
867
|
+
perms = int(perms, 8)
|
|
868
|
+
except:
|
|
869
|
+
self._finish_job(jobname, -1, '权限值输入有误!')
|
|
870
|
+
return
|
|
871
|
+
|
|
872
|
+
for path in paths:
|
|
873
|
+
result = await shell.async_task(file.chmod, path, perms, option == '-R')
|
|
874
|
+
if result == True:
|
|
875
|
+
code = 0
|
|
876
|
+
msg = '权限修改成功!'
|
|
877
|
+
else:
|
|
878
|
+
code = -1
|
|
879
|
+
msg = f'修改 {path} 的权限时失败!'
|
|
880
|
+
break
|
|
881
|
+
|
|
882
|
+
self._finish_job(jobname, code, msg)
|
|
883
|
+
|
|
884
|
+
async def wget(self, url, path):
|
|
885
|
+
jobname = 'wget_%s' % tornado.escape.url_escape(url)
|
|
886
|
+
if not self._start_job(jobname):
|
|
887
|
+
return
|
|
888
|
+
|
|
889
|
+
self._update_job(jobname, 2, f'正在下载 {url}...')
|
|
890
|
+
|
|
891
|
+
if Path(path).is_dir():
|
|
892
|
+
cmd = 'wget -q "%s" --directory-prefix=%s' % (quote(url), quote(path))
|
|
893
|
+
else:
|
|
894
|
+
cmd = 'wget -q "%s" -O %s' % (quote(url), quote(path))
|
|
895
|
+
result, output = await shell.async_command(cmd)
|
|
896
|
+
if result == 0:
|
|
897
|
+
code = 0
|
|
898
|
+
msg = '下载成功!'
|
|
899
|
+
else:
|
|
900
|
+
code = -1
|
|
901
|
+
msg = '下载失败!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
902
|
+
|
|
903
|
+
self._finish_job(jobname, code, msg)
|
|
904
|
+
|
|
905
|
+
async def mysql_fupdatepwd(self, password):
|
|
906
|
+
jobname = 'mysql_fupdatepwd'
|
|
907
|
+
if not self._start_job(jobname):
|
|
908
|
+
return
|
|
909
|
+
|
|
910
|
+
self._update_job(jobname, 2, '正在检测 MySQL 服务状态...')
|
|
911
|
+
cmd = 'service mysqld status'
|
|
912
|
+
result, output = await shell.async_command(cmd)
|
|
913
|
+
isstopped = 'stopped' in output
|
|
914
|
+
|
|
915
|
+
if not isstopped:
|
|
916
|
+
self._update_job(jobname, 2, '正在停止 MySQL 服务...')
|
|
917
|
+
cmd = 'service mysqld stop'
|
|
918
|
+
result, output = await shell.async_command(cmd)
|
|
919
|
+
if result != 0:
|
|
920
|
+
self._finish_job(jobname, -1, '停止 MySQL 服务时出错!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>'))
|
|
921
|
+
return
|
|
922
|
+
|
|
923
|
+
self._update_job(jobname, 2, '正在启用 MySQL 恢复模式...')
|
|
924
|
+
manually = False
|
|
925
|
+
cmd = 'service mysqld startsos'
|
|
926
|
+
result, output = await shell.async_command(cmd)
|
|
927
|
+
if result != 0:
|
|
928
|
+
manually = True
|
|
929
|
+
cmd = 'mysqld_safe --skip-grant-tables --skip-networking'
|
|
930
|
+
p = Popen(cmd, stdout=PIPE, stderr=STDOUT, close_fds=True, shell=True)
|
|
931
|
+
if not p:
|
|
932
|
+
self._finish_job(jobname, -1, '启用 MySQL 恢复模式时出错!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>'))
|
|
933
|
+
return
|
|
934
|
+
|
|
935
|
+
if manually:
|
|
936
|
+
time.sleep(2)
|
|
937
|
+
|
|
938
|
+
error = False
|
|
939
|
+
self._update_job(jobname, 2, '正在强制重置 root 密码...')
|
|
940
|
+
if not mysql.fupdatepwd(password):
|
|
941
|
+
error = True
|
|
942
|
+
|
|
943
|
+
if manually:
|
|
944
|
+
result = await shell.async_task(mysql.shutdown, password)
|
|
945
|
+
if result:
|
|
946
|
+
self._update_job(jobname, 0, '成功停止 MySQL 服务!')
|
|
947
|
+
else:
|
|
948
|
+
self._update_job(jobname, -1, '停止 MySQL 服务失败!')
|
|
949
|
+
p.terminate()
|
|
950
|
+
p.wait()
|
|
951
|
+
|
|
952
|
+
msg = ''
|
|
953
|
+
if not isstopped:
|
|
954
|
+
if error:
|
|
955
|
+
msg = '重置 root 密码时发生错误!正在重启 MySQL 服务...'
|
|
956
|
+
self._update_job(jobname, -1, msg)
|
|
957
|
+
else:
|
|
958
|
+
self._update_job(jobname, 2, '正在重启 MySQL 服务...')
|
|
959
|
+
if manually:
|
|
960
|
+
cmd = 'service mysqld start'
|
|
961
|
+
else:
|
|
962
|
+
cmd = 'service mysqld restart'
|
|
963
|
+
else:
|
|
964
|
+
if error:
|
|
965
|
+
msg = '重置 root 密码时发生错误!正在停止 MySQL 服务...'
|
|
966
|
+
self._update_job(jobname, -1, msg)
|
|
967
|
+
else:
|
|
968
|
+
self._update_job(jobname, 2, '正在停止 MySQL 服务...')
|
|
969
|
+
if manually:
|
|
970
|
+
cmd = ''
|
|
971
|
+
else:
|
|
972
|
+
cmd = 'service mysqld stop'
|
|
973
|
+
|
|
974
|
+
if not cmd:
|
|
975
|
+
if error:
|
|
976
|
+
code = -1
|
|
977
|
+
msg = '%sOK' % msg
|
|
978
|
+
else:
|
|
979
|
+
code = 0
|
|
980
|
+
msg = 'root 密码重置成功!'
|
|
981
|
+
else:
|
|
982
|
+
result, output = await shell.async_command(cmd)
|
|
983
|
+
if result == 0:
|
|
984
|
+
if error:
|
|
985
|
+
code = -1
|
|
986
|
+
msg = '%sOK' % msg
|
|
987
|
+
else:
|
|
988
|
+
code = 0
|
|
989
|
+
msg = 'root 密码重置成功!'
|
|
990
|
+
else:
|
|
991
|
+
if error:
|
|
992
|
+
code = -1
|
|
993
|
+
msg = '%sOK' % msg
|
|
994
|
+
else:
|
|
995
|
+
code = -1
|
|
996
|
+
msg = 'root 密码重置成功,但在操作服务时出错!<p style="margin:10px">%s</p>' % output.strip().replace('\n', '<br>')
|
|
997
|
+
|
|
998
|
+
self._finish_job(jobname, code, msg)
|
|
999
|
+
|
|
1000
|
+
async def mysql_databases(self, password):
|
|
1001
|
+
jobname = 'mysql_databases'
|
|
1002
|
+
if not self._start_job(jobname):
|
|
1003
|
+
return
|
|
1004
|
+
|
|
1005
|
+
self._update_job(jobname, 2, '正在获取数据库列表...')
|
|
1006
|
+
dbs = []
|
|
1007
|
+
dbs = await shell.async_task(mysql.show_databases, password)
|
|
1008
|
+
if dbs:
|
|
1009
|
+
code = 0
|
|
1010
|
+
msg = '获取数据库列表成功!'
|
|
1011
|
+
else:
|
|
1012
|
+
code = -1
|
|
1013
|
+
msg = '获取数据库列表失败!'
|
|
1014
|
+
|
|
1015
|
+
self._finish_job(jobname, code, msg, dbs)
|
|
1016
|
+
|
|
1017
|
+
async def mysql_users(self, password, dbname=None):
|
|
1018
|
+
if not dbname:
|
|
1019
|
+
jobname = 'mysql_users'
|
|
1020
|
+
else:
|
|
1021
|
+
jobname = 'mysql_users_%s' % dbname
|
|
1022
|
+
if not self._start_job(jobname):
|
|
1023
|
+
return
|
|
1024
|
+
|
|
1025
|
+
if not dbname:
|
|
1026
|
+
self._update_job(jobname, 2, '正在获取用户列表...')
|
|
1027
|
+
else:
|
|
1028
|
+
self._update_job(jobname, 2, f'正在获取数据库 {dbname} 的用户列表...')
|
|
1029
|
+
|
|
1030
|
+
users = []
|
|
1031
|
+
users = await shell.async_task(mysql.show_users, password, dbname)
|
|
1032
|
+
if users:
|
|
1033
|
+
code = 0
|
|
1034
|
+
msg = '获取用户列表成功!'
|
|
1035
|
+
else:
|
|
1036
|
+
code = -1
|
|
1037
|
+
msg = '获取用户列表失败!'
|
|
1038
|
+
|
|
1039
|
+
self._finish_job(jobname, code, msg, users)
|
|
1040
|
+
|
|
1041
|
+
async def mysql_dbinfo(self, password, dbname):
|
|
1042
|
+
jobname = 'mysql_dbinfo_%s' % dbname
|
|
1043
|
+
if not self._start_job(jobname):
|
|
1044
|
+
return
|
|
1045
|
+
|
|
1046
|
+
self._update_job(jobname, 2, '正在获取数据库 %s 的信息...' % dbname)
|
|
1047
|
+
dbinfo = False
|
|
1048
|
+
dbinfo = await shell.async_task(mysql.show_database, password, dbname)
|
|
1049
|
+
if dbinfo:
|
|
1050
|
+
code = 0
|
|
1051
|
+
msg = '获取数据库 %s 的信息成功!' % dbname
|
|
1052
|
+
else:
|
|
1053
|
+
code = -1
|
|
1054
|
+
msg = '获取数据库 %s 的信息失败!' % dbname
|
|
1055
|
+
|
|
1056
|
+
self._finish_job(jobname, code, msg, dbinfo)
|
|
1057
|
+
|
|
1058
|
+
async def mysql_rename(self, password, dbname, newname):
|
|
1059
|
+
jobname = 'mysql_rename_%s' % dbname
|
|
1060
|
+
if not self._start_job(jobname):
|
|
1061
|
+
return
|
|
1062
|
+
|
|
1063
|
+
self._update_job(jobname, 2, f'正在重命名 {dbname}...')
|
|
1064
|
+
result = await shell.async_task(mysql.rename_database, password, dbname, newname)
|
|
1065
|
+
if result == True:
|
|
1066
|
+
code = 0
|
|
1067
|
+
msg = f'{dbname} 重命名成功!'
|
|
1068
|
+
else:
|
|
1069
|
+
code = -1
|
|
1070
|
+
msg = f'{dbname} 重命名失败!'
|
|
1071
|
+
|
|
1072
|
+
self._finish_job(jobname, code, msg)
|
|
1073
|
+
|
|
1074
|
+
async def mysql_create(self, password, dbname, collation):
|
|
1075
|
+
jobname = f'mysql_create_{dbname}'
|
|
1076
|
+
if not self._start_job(jobname):
|
|
1077
|
+
return
|
|
1078
|
+
|
|
1079
|
+
self._update_job(jobname, 2, f'正在创建 {dbname}...')
|
|
1080
|
+
result = await shell.async_task(mysql.create_database, password, dbname, collation=collation)
|
|
1081
|
+
if result == True:
|
|
1082
|
+
code = 0
|
|
1083
|
+
msg = f'{dbname} 创建成功!'
|
|
1084
|
+
else:
|
|
1085
|
+
code = -1
|
|
1086
|
+
msg = f'{dbname} 创建失败!'
|
|
1087
|
+
|
|
1088
|
+
self._finish_job(jobname, code, msg)
|
|
1089
|
+
|
|
1090
|
+
async def mysql_export(self, password, dbname, path):
|
|
1091
|
+
jobname = f'mysql_export_{dbname}'
|
|
1092
|
+
if not self._start_job(jobname):
|
|
1093
|
+
return
|
|
1094
|
+
|
|
1095
|
+
self._update_job(jobname, 2, f'正在导出 {dbname}...')
|
|
1096
|
+
result = await shell.async_task(mysql.export_database, password, dbname, path)
|
|
1097
|
+
if result == True:
|
|
1098
|
+
code = 0
|
|
1099
|
+
msg = f'{dbname} 导出成功!'
|
|
1100
|
+
else:
|
|
1101
|
+
code = -1
|
|
1102
|
+
msg = f'{dbname} 导出失败!'
|
|
1103
|
+
|
|
1104
|
+
self._finish_job(jobname, code, msg)
|
|
1105
|
+
|
|
1106
|
+
async def mysql_drop(self, password, dbname):
|
|
1107
|
+
jobname = f'mysql_drop_{dbname}'
|
|
1108
|
+
if not self._start_job(jobname):
|
|
1109
|
+
return
|
|
1110
|
+
|
|
1111
|
+
self._update_job(jobname, 2, f'正在删除 {dbname}...')
|
|
1112
|
+
result = await shell.async_task(mysql.drop_database, password, dbname)
|
|
1113
|
+
if result == True:
|
|
1114
|
+
code = 0
|
|
1115
|
+
msg = f'{dbname} 删除成功!'
|
|
1116
|
+
else:
|
|
1117
|
+
code = -1
|
|
1118
|
+
msg = f'{dbname} 删除失败!'
|
|
1119
|
+
|
|
1120
|
+
self._finish_job(jobname, code, msg)
|
|
1121
|
+
|
|
1122
|
+
async def mysql_createuser(self, password, user, host, pwd=None):
|
|
1123
|
+
username = f'{user}@{host}'
|
|
1124
|
+
jobname = f'mysql_createuser_{username}'
|
|
1125
|
+
if not self._start_job(jobname):
|
|
1126
|
+
return
|
|
1127
|
+
|
|
1128
|
+
self._update_job(jobname, 2, f'正在添加用户 {username}...')
|
|
1129
|
+
result = await shell.async_task(mysql.create_user, password, user, host, pwd)
|
|
1130
|
+
if result is True:
|
|
1131
|
+
code = 0
|
|
1132
|
+
msg = f'用户 {username} 添加成功!'
|
|
1133
|
+
else:
|
|
1134
|
+
code = -1
|
|
1135
|
+
msg = f'用户 {username} 添加失败!'
|
|
1136
|
+
|
|
1137
|
+
self._finish_job(jobname, code, msg)
|
|
1138
|
+
|
|
1139
|
+
async def mysql_userprivs(self, password, user, host):
|
|
1140
|
+
username = f'{user}@{host}'
|
|
1141
|
+
jobname = f'mysql_userprivs_{username}'
|
|
1142
|
+
if not self._start_job(jobname):
|
|
1143
|
+
return
|
|
1144
|
+
|
|
1145
|
+
self._update_job(jobname, 2, f'正在获取用户 {username} 的权限...')
|
|
1146
|
+
|
|
1147
|
+
privs = {'global': {}, 'bydb': {}}
|
|
1148
|
+
globalprivs = await shell.async_task(mysql.show_user_globalprivs, password, user, host)
|
|
1149
|
+
if globalprivs != False:
|
|
1150
|
+
code = 0
|
|
1151
|
+
msg = f'获取用户 {username} 的全局权限成功!'
|
|
1152
|
+
privs['global'] = globalprivs
|
|
1153
|
+
else:
|
|
1154
|
+
code = -1
|
|
1155
|
+
msg = f'获取用户 {username} 的全局权限失败!'
|
|
1156
|
+
privs = False
|
|
1157
|
+
|
|
1158
|
+
if privs:
|
|
1159
|
+
dbprivs = await shell.async_task(mysql.show_user_dbprivs, password, user, host)
|
|
1160
|
+
if dbprivs != False:
|
|
1161
|
+
code = 0
|
|
1162
|
+
msg = f'获取用户 {username} 的数据库权限成功!'
|
|
1163
|
+
privs['bydb'] = dbprivs
|
|
1164
|
+
else:
|
|
1165
|
+
code = -1
|
|
1166
|
+
msg = f'获取用户 {username} 的数据库权限失败!'
|
|
1167
|
+
privs = False
|
|
1168
|
+
|
|
1169
|
+
self._finish_job(jobname, code, msg, privs)
|
|
1170
|
+
|
|
1171
|
+
async def mysql_updateuserprivs(self, password, user, host, privs, dbname=None):
|
|
1172
|
+
username = f'{user}@{host}'
|
|
1173
|
+
if dbname:
|
|
1174
|
+
jobname = f'mysql_updateuserprivs_{username}_{dbname}'
|
|
1175
|
+
else:
|
|
1176
|
+
jobname = f'mysql_updateuserprivs_{username}'
|
|
1177
|
+
if not self._start_job(jobname):
|
|
1178
|
+
return
|
|
1179
|
+
|
|
1180
|
+
if dbname:
|
|
1181
|
+
self._update_job(jobname, 2, f'正在更新用户 {username} 在数据库 {dbname} 中的权限...')
|
|
1182
|
+
else:
|
|
1183
|
+
self._update_job(jobname, 2, f'正在更新用户 {username} 的权限...')
|
|
1184
|
+
|
|
1185
|
+
rt = await shell.async_task(mysql.update_user_privs, password, user, host, privs, dbname)
|
|
1186
|
+
if rt != False:
|
|
1187
|
+
code = 0
|
|
1188
|
+
msg = f'用户 {username} 的权限更新成功!'
|
|
1189
|
+
else:
|
|
1190
|
+
code = -1
|
|
1191
|
+
msg = f'用户 {username} 的权限更新失败!'
|
|
1192
|
+
|
|
1193
|
+
self._finish_job(jobname, code, msg)
|
|
1194
|
+
|
|
1195
|
+
async def mysql_setuserpassword(self, password, user, host, pwd):
|
|
1196
|
+
username = f'{user}@{host}'
|
|
1197
|
+
jobname = f'mysql_setuserpassword_{username}'
|
|
1198
|
+
if not self._start_job(jobname):
|
|
1199
|
+
return
|
|
1200
|
+
|
|
1201
|
+
self._update_job(jobname, 2, f'正在更新用户 {username} 的密码...')
|
|
1202
|
+
|
|
1203
|
+
rt = await shell.async_task(mysql.set_user_password, password, user, host, pwd)
|
|
1204
|
+
if rt != False:
|
|
1205
|
+
code = 0
|
|
1206
|
+
msg = f'用户 {username} 的密码更新成功 !'
|
|
1207
|
+
else:
|
|
1208
|
+
code = -1
|
|
1209
|
+
msg = f'用户 {username} 的密码更新失败 !'
|
|
1210
|
+
|
|
1211
|
+
self._finish_job(jobname, code, msg)
|
|
1212
|
+
|
|
1213
|
+
async def mysql_dropuser(self, password, user, host):
|
|
1214
|
+
username = f'{user}@{host}'
|
|
1215
|
+
jobname = f'mysql_dropuser_{username}'
|
|
1216
|
+
if not self._start_job(jobname):
|
|
1217
|
+
return
|
|
1218
|
+
|
|
1219
|
+
self._update_job(jobname, 2, f'正在删除用户 {username}...')
|
|
1220
|
+
|
|
1221
|
+
rt = await shell.async_task(mysql.drop_user, password, user, host)
|
|
1222
|
+
if rt != False:
|
|
1223
|
+
code = 0
|
|
1224
|
+
msg = f'用户 {username} 删除成功 !'
|
|
1225
|
+
else:
|
|
1226
|
+
code = -1
|
|
1227
|
+
msg = f'用户 {username} 删除失败 !'
|
|
1228
|
+
|
|
1229
|
+
self._finish_job(jobname, code, msg)
|
|
1230
|
+
|
|
1231
|
+
async def ssh_genkey(self, path, password=''):
|
|
1232
|
+
jobname = 'ssh_genkey'
|
|
1233
|
+
if not self._start_job(jobname):
|
|
1234
|
+
return
|
|
1235
|
+
|
|
1236
|
+
self._update_job(jobname, 2, '正在生成密钥对...')
|
|
1237
|
+
|
|
1238
|
+
rt = await shell.async_task(ssh.genkey, path, password)
|
|
1239
|
+
if rt != False:
|
|
1240
|
+
code = 0
|
|
1241
|
+
msg = '密钥对生成成功 !'
|
|
1242
|
+
else:
|
|
1243
|
+
code = -1
|
|
1244
|
+
msg = '密钥对生成失败 !'
|
|
1245
|
+
|
|
1246
|
+
self._finish_job(jobname, code, msg)
|
|
1247
|
+
|
|
1248
|
+
async def ssh_chpasswd(self, path, oldpassword, newpassword=''):
|
|
1249
|
+
jobname = 'ssh_chpasswd'
|
|
1250
|
+
if not self._start_job(jobname):
|
|
1251
|
+
return
|
|
1252
|
+
|
|
1253
|
+
self._update_job(jobname, 2, '正在修改私钥密码...')
|
|
1254
|
+
|
|
1255
|
+
rt = await shell.async_task(ssh.chpasswd, path, oldpassword, newpassword)
|
|
1256
|
+
if rt != False:
|
|
1257
|
+
code = 0
|
|
1258
|
+
msg = '私钥密码修改成功!'
|
|
1259
|
+
else:
|
|
1260
|
+
code = -1
|
|
1261
|
+
msg = '私钥密码修改失败!'
|
|
1262
|
+
|
|
1263
|
+
self._finish_job(jobname, code, msg)
|
|
1264
|
+
|
|
1265
|
+
async def inpanel_install(self, ssh_ip, ssh_port, ssh_user, ssh_password, instance_name, accessnet, accessport=None, accesskey=None):
|
|
1266
|
+
jobname = f'remote_inpanel_install_{ssh_ip}'
|
|
1267
|
+
if not self._start_job(jobname):
|
|
1268
|
+
return
|
|
1269
|
+
|
|
1270
|
+
self._update_job(jobname, 2, f'正在将 InPanel 安装到 {ssh_ip}...')
|
|
1271
|
+
|
|
1272
|
+
result = await shell.async_task(remote.inpanel_install, ssh_ip, ssh_port, ssh_user, ssh_password, accesskey=accesskey, inpanel_port=accessport)
|
|
1273
|
+
if result == True:
|
|
1274
|
+
code = 0
|
|
1275
|
+
msg = 'InPanel 安装成功!'
|
|
1276
|
+
self.config.set('inpanel', instance_name, f'{accesskey}|{accessnet}|{accessport}')
|
|
1277
|
+
else:
|
|
1278
|
+
code = -1
|
|
1279
|
+
msg = 'InPanel 安装过程中发生错误!'
|
|
1280
|
+
|
|
1281
|
+
self._finish_job(jobname, code, msg)
|
|
1282
|
+
|
|
1283
|
+
async def inpanel_uninstall(self, ssh_ip, ssh_port, ssh_user, ssh_password, instance_name):
|
|
1284
|
+
jobname = f'remote_inpanel_uninstall_{ssh_ip}'
|
|
1285
|
+
if not self._start_job(jobname):
|
|
1286
|
+
return
|
|
1287
|
+
|
|
1288
|
+
self._update_job(jobname, 2, f'正在卸载 {ssh_ip} 上的 InPanel...')
|
|
1289
|
+
result = await shell.async_task(remote.inpanel_uninstall, ssh_ip, ssh_port, ssh_user, ssh_password)
|
|
1290
|
+
if result == True:
|
|
1291
|
+
code = 0
|
|
1292
|
+
msg = 'InPanel 卸载成功!'
|
|
1293
|
+
try:
|
|
1294
|
+
self.config.remove_option('inpanel', instance_name)
|
|
1295
|
+
except:
|
|
1296
|
+
pass
|
|
1297
|
+
else:
|
|
1298
|
+
code = -1
|
|
1299
|
+
msg = 'InPanel 卸载过程中发生错误!'
|
|
1300
|
+
|
|
1301
|
+
self._finish_job(jobname, code, msg)
|
|
1302
|
+
|
|
1303
|
+
async def inpanel_config(self, ssh_ip, ssh_port, ssh_user, ssh_password, accesskey=None):
|
|
1304
|
+
jobname = f'remote_inpanel_config_{ssh_ip}'
|
|
1305
|
+
if not self._start_job(jobname):
|
|
1306
|
+
return
|
|
1307
|
+
|
|
1308
|
+
self._update_job(jobname, 2, f'正在更新 {ssh_ip} 上的 InPanel 配置...')
|
|
1309
|
+
|
|
1310
|
+
result = await shell.async_task(remote.inpanel_config, ssh_ip, ssh_port, ssh_user, ssh_password, accesskey=accesskey)
|
|
1311
|
+
if result == True:
|
|
1312
|
+
code = 0
|
|
1313
|
+
msg = 'InPanel 配置更新成功!'
|
|
1314
|
+
else:
|
|
1315
|
+
code = -1
|
|
1316
|
+
msg = 'InPanel 配置更新过程中发生错误!'
|
|
1317
|
+
|
|
1318
|
+
self._finish_job(jobname, code, msg)
|
|
1319
|
+
|
|
1320
|
+
async def uploadtoftp(self, address, account, password, source, target):
|
|
1321
|
+
jobname = f'upload_to_ftp_{address}_{source}_{target}'
|
|
1322
|
+
if not self._start_job(jobname):
|
|
1323
|
+
return
|
|
1324
|
+
|
|
1325
|
+
if not Path(source).exists():
|
|
1326
|
+
self._finish_job(jobname, -1, '传输失败!文件不存在')
|
|
1327
|
+
return
|
|
1328
|
+
|
|
1329
|
+
self._update_job(jobname, 2, f'正在传输文件 {source}...')
|
|
1330
|
+
result = await shell.async_task(ftp.uploadtoftp, address, account, password, source, target)
|
|
1331
|
+
if result == True:
|
|
1332
|
+
code = 0
|
|
1333
|
+
msg = f'文件 {source} 已成功传输到 {address} 服务器!'
|
|
1334
|
+
else:
|
|
1335
|
+
code = -1
|
|
1336
|
+
msg = '文件传输失败!'
|
|
1337
|
+
self._finish_job(jobname, code, msg)
|