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/httpd.py
ADDED
|
@@ -0,0 +1,1205 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2017-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 Apache HTTP Server Management.'''
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from glob import glob
|
|
14
|
+
from io import StringIO
|
|
15
|
+
from json import loads
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from string import punctuation
|
|
18
|
+
|
|
19
|
+
from ..base import COMMENTFLAG, GENBY, config_path
|
|
20
|
+
from .config import Config
|
|
21
|
+
from ..utils import is_valid_domain, is_valid_ip, is_valid_ipv4, is_valid_ipv6
|
|
22
|
+
|
|
23
|
+
# load httpd module config
|
|
24
|
+
httpd_config = Config(str(Path(config_path) / 'module/httpd.ini'))
|
|
25
|
+
# print('httpd_config', httpd_config.get_config())
|
|
26
|
+
base_path = httpd_config.get('base', 'path')
|
|
27
|
+
base_config = httpd_config.get('base', 'config')
|
|
28
|
+
base_servers = httpd_config.get('base', 'servers')
|
|
29
|
+
|
|
30
|
+
if Path(base_path).exists():
|
|
31
|
+
HTTPDCONF = base_path
|
|
32
|
+
else:
|
|
33
|
+
HTTPDCONF = '/etc/httpd/'
|
|
34
|
+
|
|
35
|
+
if Path(base_config).exists():
|
|
36
|
+
APACHECONF = base_config
|
|
37
|
+
else:
|
|
38
|
+
APACHECONF = '/etc/httpd/conf/httpd.conf'
|
|
39
|
+
|
|
40
|
+
if Path(base_servers).exists():
|
|
41
|
+
SERVERCONF = base_servers
|
|
42
|
+
else:
|
|
43
|
+
SERVERCONF = '/etc/httpd/conf.d/'
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
CONFIGS = {
|
|
47
|
+
'servertokens': 'os',
|
|
48
|
+
'serverroot': '/etc/httpd',
|
|
49
|
+
'timeout': 60,
|
|
50
|
+
'defaulttype': 'text/plain',
|
|
51
|
+
'documentroot': '/var/www/html',
|
|
52
|
+
'directoryindex': 'index.html index.htm index.php',
|
|
53
|
+
'adddefaultcharset': 'utf-8',
|
|
54
|
+
'listen': 80,
|
|
55
|
+
'serveradmin': 'root@localhost',
|
|
56
|
+
'servername': 'www@localhost',
|
|
57
|
+
'namevirtualhost': '*:80',
|
|
58
|
+
'keepalive': 'off',
|
|
59
|
+
'maxkeepaliverequests': 100,
|
|
60
|
+
'keepalivetimeout': 15,
|
|
61
|
+
'usecanonicalname': 'off',
|
|
62
|
+
'accessfilename': '.htaccess',
|
|
63
|
+
'typesconfig': '/etc/mime.types',
|
|
64
|
+
'errorlog': 'logs/error_log',
|
|
65
|
+
'loglevel': 'debug', # info, notice, warn, error, crit, alert, emerg
|
|
66
|
+
'serversignature': 'on',
|
|
67
|
+
'indexoptions': 'fancyindexing versionsort namewidth=* htmltable charset=utf-8',
|
|
68
|
+
'alias': 'alias',
|
|
69
|
+
'addlanguage': '',
|
|
70
|
+
'loadmodule': '',
|
|
71
|
+
'scriptalias': '',
|
|
72
|
+
'addtype': '',
|
|
73
|
+
'addicon': '',
|
|
74
|
+
'addiconbytype': '',
|
|
75
|
+
'include': '',
|
|
76
|
+
'aaa': '',
|
|
77
|
+
'bbb': ''
|
|
78
|
+
}
|
|
79
|
+
DIRECTIVES = {
|
|
80
|
+
'acceptfilter': ('server'),
|
|
81
|
+
'acceptpathinfo': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
82
|
+
'accessfilename': ('server', 'virtualhost'),
|
|
83
|
+
'adddefaultcharset': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
84
|
+
'allowencodedslashes': ('server', 'virtualhost'),
|
|
85
|
+
'allowoverride': ('directory'),
|
|
86
|
+
'allowoverridelist': ('directory'),
|
|
87
|
+
'cgimapextension': ('directory', 'htaccess'),
|
|
88
|
+
'cgipassauth': ('directory', 'htaccess'),
|
|
89
|
+
'cgivar': ('directory', 'htaccess'),
|
|
90
|
+
'contentdigest': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
91
|
+
'defaultruntimedir': ('server'),
|
|
92
|
+
'defaulttype': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
93
|
+
'define': ('server', 'virtualhost', 'directory'),
|
|
94
|
+
'directory': ('server', 'virtualhost'),
|
|
95
|
+
'directorymatch': ('server', 'virtualhost'),
|
|
96
|
+
'documentroot': ('server', 'virtualhost'),
|
|
97
|
+
'else': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
98
|
+
'elseif': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
99
|
+
'enablemmap': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
100
|
+
'enablesendfile': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
101
|
+
'error': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
102
|
+
'errordocument': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
103
|
+
'errorlog': ('server', 'virtualhost'),
|
|
104
|
+
'errorlogformat': ('server', 'virtualhost'),
|
|
105
|
+
'extendedstatus': ('server'),
|
|
106
|
+
'fileetag': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
107
|
+
'files': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
108
|
+
'filesmatch': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
109
|
+
'forcetype': ('directory', 'htaccess'),
|
|
110
|
+
'gprofdir': ('server', 'virtualhost'),
|
|
111
|
+
'hostnamelookups': ('server', 'virtualhost', 'directory'),
|
|
112
|
+
'httpprotocoloptions': ('server', 'virtualhost'),
|
|
113
|
+
'if': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
114
|
+
'ifdefine': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
115
|
+
'ifdirective': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
116
|
+
'iffile': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
117
|
+
'ifmodule': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
118
|
+
'ifsection': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
119
|
+
'include': ('server', 'virtualhost', 'directory'),
|
|
120
|
+
'includeoptional': ('server', 'virtualhost', 'directory'),
|
|
121
|
+
'keepalive': ('server', 'virtualhost'),
|
|
122
|
+
'keepalivetimeout': ('server', 'virtualhost'),
|
|
123
|
+
'limit': ('directory', 'htaccess'),
|
|
124
|
+
'limitexcept': ('directory', 'htaccess'),
|
|
125
|
+
'limitinternalrecursion': ('server', 'virtualhost'),
|
|
126
|
+
'limitrequestbody': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
127
|
+
'limitrequestfields': ('server', 'virtualhost'),
|
|
128
|
+
'limitrequestfieldsize': ('server', 'virtualhost'),
|
|
129
|
+
'limitrequestline': ('server', 'virtualhost'),
|
|
130
|
+
'limitxmlrequestbody': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
131
|
+
'location': ('server', 'virtualhost'),
|
|
132
|
+
'locationmatch': ('server', 'virtualhost'),
|
|
133
|
+
'loglevel': ('server', 'virtualhost', 'directory'),
|
|
134
|
+
'maxkeepaliverequests': ('server', 'virtualhost'),
|
|
135
|
+
'maxrangeoverlaps': ('server', 'virtualhost', 'directory'),
|
|
136
|
+
'maxrangereversals': ('server', 'virtualhost', 'directory'),
|
|
137
|
+
'maxranges': ('server', 'virtualhost', 'directory'),
|
|
138
|
+
'mergeslashes': ('server', 'virtualhost'),
|
|
139
|
+
'mergetrailers': ('server', 'virtualhost'),
|
|
140
|
+
'mutex': ('server'),
|
|
141
|
+
'namevirtualhost': ('server'),
|
|
142
|
+
'options': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
143
|
+
'protocol': ('server', 'virtualhost'),
|
|
144
|
+
'protocols': ('server', 'virtualhost'),
|
|
145
|
+
'protocolshonororder': ('server', 'virtualhost'),
|
|
146
|
+
'qualifyredirecturl': ('server', 'virtualhost', 'directory'),
|
|
147
|
+
'regexdefaultoptions': ('server'),
|
|
148
|
+
'registerhttpmethod': ('server'),
|
|
149
|
+
'rlimitcpu': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
150
|
+
'rlimitmem': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
151
|
+
'rlimitnproc': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
152
|
+
'scriptinterpretersource': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
153
|
+
'seerequesttail': ('server'),
|
|
154
|
+
'serveradmin': ('server', 'virtualhost'),
|
|
155
|
+
'serveralias': ('virtualhost'),
|
|
156
|
+
'servername': ('server', 'virtualhost'),
|
|
157
|
+
'serverpath': ('virtualhost'),
|
|
158
|
+
'serverroot': ('server'),
|
|
159
|
+
'serversignature': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
160
|
+
'servertokens': ('server'),
|
|
161
|
+
'sethandler': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
162
|
+
'setinputfilter': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
163
|
+
'setoutputfilter': ('server', 'virtualhost', 'directory', 'htaccess'),
|
|
164
|
+
'timeout': ('server', 'virtualhost'),
|
|
165
|
+
'traceenable': ('server', 'virtualhost'),
|
|
166
|
+
'undefine': ('server'),
|
|
167
|
+
'usecanonicalname': ('server', 'virtualhost', 'directory'),
|
|
168
|
+
'usecanonicalphysicalport': ('server', 'virtualhost', 'directory'),
|
|
169
|
+
'virtualhost': ('server'),
|
|
170
|
+
'aaa': (),
|
|
171
|
+
'bbb': ()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
GZIP = r'''<IfModule mod_deflate.c>
|
|
175
|
+
DeflateCompressionLevel 6
|
|
176
|
+
AddOutputFilterByType DEFLATE text/plain
|
|
177
|
+
AddOutputFilterByType DEFLATE text/html
|
|
178
|
+
AddOutputFilterByType DEFLATE text/php
|
|
179
|
+
AddOutputFilterByType DEFLATE text/xml
|
|
180
|
+
AddOutputFilterByType DEFLATE text/css
|
|
181
|
+
AddOutputFilterByType DEFLATE text/javascript
|
|
182
|
+
AddOutputFilterByType DEFLATE application/xhtml+xml
|
|
183
|
+
AddOutputFilterByType DEFLATE application/xml
|
|
184
|
+
AddOutputFilterByType DEFLATE application/rss+xml
|
|
185
|
+
AddOutputFilterByType DEFLATE application/atom_xml
|
|
186
|
+
AddOutputFilterByType DEFLATE application/javascript
|
|
187
|
+
AddOutputFilterByType DEFLATE application/x-javascript
|
|
188
|
+
AddOutputFilterByType DEFLATE application/x-httpd-php
|
|
189
|
+
AddOutputFilterByType DEFLATE application/x-font-ttf
|
|
190
|
+
AddOutputFilterByType DEFLATE image/svg+xml
|
|
191
|
+
AddOutputFilterByType DEFLATE image/gif image/png image/jpe image/swf image/jpeg image/bmp
|
|
192
|
+
# Don’t compress images and other
|
|
193
|
+
BrowserMatch ^Mozilla/4 gzip-only-text/html
|
|
194
|
+
BrowserMatch ^Mozilla/4\.0[678] no-gzip
|
|
195
|
+
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
|
|
196
|
+
SetEnvIfNoCase Request_URI .(?:html|htm)$ no-gzip dont-varySetEnvIfNoCase
|
|
197
|
+
#SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
|
|
198
|
+
SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
|
|
199
|
+
SetEnvIfNoCase Request_URI .(?:pdf|doc)$ no-gzip dont-vary
|
|
200
|
+
</IfModule>'''
|
|
201
|
+
|
|
202
|
+
def web_handler(context):
|
|
203
|
+
'''for web server'''
|
|
204
|
+
action = context.get_argument('action', '')
|
|
205
|
+
if action == 'getservers':
|
|
206
|
+
sites = getservers()
|
|
207
|
+
context.write({'code': 0, 'msg': '', 'data': sites})
|
|
208
|
+
|
|
209
|
+
elif action in ('enableserver', 'disableserver', 'deleteserver'):
|
|
210
|
+
ip = context.get_argument('ip', '')
|
|
211
|
+
port = context.get_argument('port', '')
|
|
212
|
+
name = context.get_argument('server_name', '')
|
|
213
|
+
handler = getattr(locals(), action)
|
|
214
|
+
opstr = {
|
|
215
|
+
'enableserver': '启用',
|
|
216
|
+
'disableserver': '停用',
|
|
217
|
+
'deleteserver': '删除',
|
|
218
|
+
}
|
|
219
|
+
if handler(name, ip, port):
|
|
220
|
+
context.write({'code': 0, 'msg': f'站点 {name}:{port} {opstr[action]}成功!'})
|
|
221
|
+
else:
|
|
222
|
+
context.write({'code': -1, 'msg': f'站点 {name}:{port} {opstr[action]}失败!'})
|
|
223
|
+
|
|
224
|
+
elif action == 'get_settings':
|
|
225
|
+
# items = context.get_argument('items', '')
|
|
226
|
+
# items = items.split(',')
|
|
227
|
+
config = loadconfig()
|
|
228
|
+
context.write({'code': 0, 'msg': '', 'data': config})
|
|
229
|
+
|
|
230
|
+
elif action == 'getserver':
|
|
231
|
+
ip = context.get_argument('ip', '')
|
|
232
|
+
port = context.get_argument('port', '')
|
|
233
|
+
name = context.get_argument('name', '')
|
|
234
|
+
serverinfo = getserver(ip, port, name)
|
|
235
|
+
if serverinfo:
|
|
236
|
+
context.write({'code': 0, 'msg': '站点信息读取成功!', 'data': serverinfo})
|
|
237
|
+
else:
|
|
238
|
+
context.write({'code': -1, 'msg': '站点不存在!'})
|
|
239
|
+
|
|
240
|
+
elif action in ('addserver', 'updateserver'):
|
|
241
|
+
setting = loads(context.get_argument('setting', '')) or {}
|
|
242
|
+
|
|
243
|
+
ip = setting.get('ip', '')
|
|
244
|
+
if ip not in ('', '*', '0.0.0.0') and not is_valid_ip(ip):
|
|
245
|
+
context.write({'code': -1, 'msg': f'{ip} 不是有效的IP地址!'})
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
port = int(setting.get('port', 0))
|
|
249
|
+
if port <= 0 or port > 65535:
|
|
250
|
+
context.write({'code': -1, 'msg': f'{setting.get("port")} 不是有效的端口号!'})
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
servername = setting.get('servername')
|
|
254
|
+
# print('servername', servername)
|
|
255
|
+
if not is_valid_domain(servername):
|
|
256
|
+
context.write({'code': -1, 'msg': f'{servername} 不是有效的域名!'})
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
documentroot = setting.get('documentroot', '')
|
|
260
|
+
if not documentroot:
|
|
261
|
+
context.write({'code': -1, 'msg': f'{documentroot} 不是有效的目录!'})
|
|
262
|
+
return
|
|
263
|
+
autocreate = setting.get('autocreate')
|
|
264
|
+
if not Path(documentroot).exists():
|
|
265
|
+
if autocreate:
|
|
266
|
+
try:
|
|
267
|
+
mkdir(documentroot)
|
|
268
|
+
except:
|
|
269
|
+
context.write({'code': -1, 'msg': f'站点目录 {documentroot} 创建失败!'})
|
|
270
|
+
return
|
|
271
|
+
else:
|
|
272
|
+
context.write({'code': -1, 'msg': f'站点目录 {documentroot} 不存在!'})
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
directoryindex = setting.get('directoryindex')
|
|
276
|
+
serveralias = setting.get('serveralias')
|
|
277
|
+
serveradmin = setting.get('serveradmin')
|
|
278
|
+
errorlog = setting.get('errorlog')
|
|
279
|
+
customlog = setting.get('customlog')
|
|
280
|
+
directory = setting.get('directory')
|
|
281
|
+
|
|
282
|
+
version = context.get_argument('version', '') # apache version
|
|
283
|
+
for diret in directory:
|
|
284
|
+
if 'path' in diret and diret['path']:
|
|
285
|
+
if not Path(diret['path']).exists() and 'autocreate' in diret and diret['autocreate']:
|
|
286
|
+
try:
|
|
287
|
+
mkdir(diret['path'])
|
|
288
|
+
except:
|
|
289
|
+
context.write({'code': -1, 'msg': '路径 %s 创建失败!' % diret['path']})
|
|
290
|
+
return
|
|
291
|
+
else:
|
|
292
|
+
context.write({'code': -1, 'msg': '请选择路径!'})
|
|
293
|
+
return
|
|
294
|
+
if action == 'addserver':
|
|
295
|
+
if not addserver(servername, ip, port, serveralias=serveralias, serveradmin=serveradmin, documentroot=documentroot, directoryindex=directoryindex, directory=directory,
|
|
296
|
+
errorlog=errorlog, customlog=customlog, version=version):
|
|
297
|
+
context.write({'code': -1, 'msg': '新站点添加失败!请检查站点域名是否重复。', 'data': setting})
|
|
298
|
+
else:
|
|
299
|
+
context.write({'code': 0, 'msg': '新站点添加成功!', 'data': setting})
|
|
300
|
+
else:
|
|
301
|
+
c_ip = context.get_argument('ip', '')
|
|
302
|
+
c_port = context.get_argument('port', '')
|
|
303
|
+
c_name = context.get_argument('name', '')
|
|
304
|
+
if not updateserver(c_name, c_ip, c_port, serveralias=serveralias, serveradmin=serveradmin, documentroot=documentroot, directoryindex=directoryindex, directory=directory,
|
|
305
|
+
errorlog=errorlog, customlog=customlog, version=version):
|
|
306
|
+
context.write({'code': -1, 'msg': '站点设置更新失败!请检查配置信息(如域名是否重复?)', 'data': setting})
|
|
307
|
+
else:
|
|
308
|
+
context.write({'code': 0, 'msg': '站点设置更新成功!', 'data': setting})
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def loadconfig(conf=None, getlineinfo=False):
|
|
312
|
+
'''Load Apache config and return a dict.
|
|
313
|
+
'''
|
|
314
|
+
if not conf:
|
|
315
|
+
conf = APACHECONF
|
|
316
|
+
if not Path(conf).is_file():
|
|
317
|
+
return False
|
|
318
|
+
return _loadconfig(conf, getlineinfo)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _loadconfig(conf, getlineinfo, config=None, context_stack=None):
|
|
322
|
+
'''parse Apache httpd.conf and include configs'''
|
|
323
|
+
if config is None:
|
|
324
|
+
configs = {}
|
|
325
|
+
else:
|
|
326
|
+
configs = config
|
|
327
|
+
|
|
328
|
+
result = {}
|
|
329
|
+
directorys = {} # 附加信息
|
|
330
|
+
|
|
331
|
+
RE_VH_START = re.compile(r'<VirtualHost(\s+)(\S+)>')
|
|
332
|
+
RE_VH_CLOSE = re.compile(r'</VirtualHost>')
|
|
333
|
+
RE_DT_START = re.compile(r'<Directory(\s+)(\S+)>')
|
|
334
|
+
RE_DT_CLOSE = re.compile(r'</Directory>')
|
|
335
|
+
with open(conf, 'r', encoding='utf-8') as f:
|
|
336
|
+
id_v = 0
|
|
337
|
+
enable = False
|
|
338
|
+
vhost = []
|
|
339
|
+
id_d = 0
|
|
340
|
+
enable_d = False
|
|
341
|
+
v_dirs = {}
|
|
342
|
+
result_d = {}
|
|
343
|
+
for line_i, line in enumerate(f):
|
|
344
|
+
out = line.strip()
|
|
345
|
+
|
|
346
|
+
line_disabled = False
|
|
347
|
+
if out.startswith(COMMENTFLAG):
|
|
348
|
+
# deal with our speical comment string
|
|
349
|
+
while out.startswith(COMMENTFLAG):
|
|
350
|
+
out = out[3:]
|
|
351
|
+
out = out.strip()
|
|
352
|
+
line_disabled = True
|
|
353
|
+
|
|
354
|
+
if not out or out.startswith('#'):
|
|
355
|
+
continue
|
|
356
|
+
|
|
357
|
+
# deal with comment and detect inpanel flag in comment
|
|
358
|
+
gen_by_inpanel = False
|
|
359
|
+
fields = out.split('#', 1)
|
|
360
|
+
if len(fields) > 1 and fields[1].strip() == GENBY:
|
|
361
|
+
gen_by_inpanel = True
|
|
362
|
+
|
|
363
|
+
out = fields[0].strip()
|
|
364
|
+
line = out.strip(';').lstrip('<').lstrip('</').rstrip('>')
|
|
365
|
+
fields = line.split()
|
|
366
|
+
key = fields[0].lower()
|
|
367
|
+
value = ' '.join(fields[1:]).strip(';')
|
|
368
|
+
# print(key, value, line)
|
|
369
|
+
|
|
370
|
+
match = RE_VH_START.search(out)
|
|
371
|
+
if match:
|
|
372
|
+
id_d = 0
|
|
373
|
+
v_dirs = {}
|
|
374
|
+
result_d[id_v] = []
|
|
375
|
+
directorys[id_v] = []
|
|
376
|
+
name_port = match.groups()[1].strip('"').strip('\'')
|
|
377
|
+
# print(name_port)
|
|
378
|
+
port = name_port.split(':')[-1]
|
|
379
|
+
ip = name_port[0:-(len(port) + 1)]
|
|
380
|
+
ip = ip.lstrip('[').rstrip(']') # for IPv6
|
|
381
|
+
vhost = [ip, port, gen_by_inpanel, line_disabled]
|
|
382
|
+
enable = True
|
|
383
|
+
enable_d = False
|
|
384
|
+
continue
|
|
385
|
+
|
|
386
|
+
# start of Directory in VirtualHost
|
|
387
|
+
match_d = RE_DT_START.search(out)
|
|
388
|
+
if enable is True and match_d:
|
|
389
|
+
v_dirs = {}
|
|
390
|
+
path = match_d.groups()[1].strip().strip('"')
|
|
391
|
+
v_dirs[id_d] = []
|
|
392
|
+
v_dirs[id_d].append('path ' + path)
|
|
393
|
+
enable_d = True
|
|
394
|
+
continue
|
|
395
|
+
|
|
396
|
+
# end of Directory in VirtualHost
|
|
397
|
+
# if '</Directory>' in out:
|
|
398
|
+
if enable_d is True and RE_DT_CLOSE.search(out):
|
|
399
|
+
result_d[id_v].append(v_dirs[id_d])
|
|
400
|
+
id_d += 1
|
|
401
|
+
enable_d = False
|
|
402
|
+
v_dirs = {}
|
|
403
|
+
continue
|
|
404
|
+
|
|
405
|
+
# merge of Directory in VirtualHost
|
|
406
|
+
if enable_d:
|
|
407
|
+
v_dirs[id_d].append(out)
|
|
408
|
+
continue
|
|
409
|
+
|
|
410
|
+
# end of VirtualHost
|
|
411
|
+
if RE_VH_CLOSE.search(out):
|
|
412
|
+
enable_d = False
|
|
413
|
+
if len(vhost) > 0:
|
|
414
|
+
result[id_v] = vhost
|
|
415
|
+
if id_v in result_d:
|
|
416
|
+
d = _parse_directory(result_d[id_v])
|
|
417
|
+
directorys[id_v] = d
|
|
418
|
+
else:
|
|
419
|
+
directorys[id_v] = []
|
|
420
|
+
id_v += 1
|
|
421
|
+
enable = False
|
|
422
|
+
continue
|
|
423
|
+
|
|
424
|
+
# merge of VirtualHost
|
|
425
|
+
if enable:
|
|
426
|
+
# print('merge', out)
|
|
427
|
+
vhost.append(out)
|
|
428
|
+
continue
|
|
429
|
+
|
|
430
|
+
if key in CONFIGS:
|
|
431
|
+
if key in ('indexoptions', 'directoryindex'):
|
|
432
|
+
configs[key] = ' '.join(str(n) for n in fields[1:])
|
|
433
|
+
elif key == 'addicon':
|
|
434
|
+
if key in configs:
|
|
435
|
+
configs[key].append({'path': fields[1], 'exts': fields[2:]})
|
|
436
|
+
else:
|
|
437
|
+
configs[key] = [{'path': fields[1], 'exts': fields[2:]}]
|
|
438
|
+
elif key == 'addiconbytype':
|
|
439
|
+
configs[key] = ' '.join(str(n) for n in fields[1:])
|
|
440
|
+
elif key == 'alias':
|
|
441
|
+
if key in configs:
|
|
442
|
+
configs[key].append({'alias': fields[1], 'origin': fields[2].strip('"')})
|
|
443
|
+
else:
|
|
444
|
+
configs[key] = [{'alias': fields[1], 'origin': fields[2].strip('"')}]
|
|
445
|
+
elif key == ('addlanguage', 'loadmodule'):
|
|
446
|
+
if key in configs:
|
|
447
|
+
configs[key].append(fields[1:])
|
|
448
|
+
else:
|
|
449
|
+
configs[key] = [fields[1:]]
|
|
450
|
+
elif key == 'listen':
|
|
451
|
+
port = fields[1].split(':')[-1]
|
|
452
|
+
ip = fields[1][0:-(len(port) + 1)].lstrip('[').rstrip(']')
|
|
453
|
+
if key in configs:
|
|
454
|
+
configs[key].append({'port': port, 'ip': ip})
|
|
455
|
+
else:
|
|
456
|
+
configs[key] = [{'port': port, 'ip': ip}]
|
|
457
|
+
elif key == 'include':
|
|
458
|
+
include_file = fields[1] if fields[1].startswith('/') else str(Path(HTTPDCONF) / fields[1])
|
|
459
|
+
include_files = glob(include_file)
|
|
460
|
+
# order by domain name, excluding tld
|
|
461
|
+
# getdm = lambda x: x.split('/')[-1].split('.')[-3::-1]
|
|
462
|
+
# include_files = sorted(include_files, lambda x,y: cmp(getdm(x), getdm(y)))
|
|
463
|
+
for subconf in include_files:
|
|
464
|
+
if Path(subconf).is_file():
|
|
465
|
+
# print(subconf, getlineinfo, configs, context_stack)
|
|
466
|
+
# print('configs', configs)
|
|
467
|
+
_loadconfig(subconf, getlineinfo, configs, context_stack)
|
|
468
|
+
else:
|
|
469
|
+
configs[key] = fields[1].strip(punctuation)
|
|
470
|
+
|
|
471
|
+
# print('directorys', directorys)
|
|
472
|
+
if 'virtualhost' not in configs:
|
|
473
|
+
configs['virtualhost'] = []
|
|
474
|
+
|
|
475
|
+
if len(result) > 0:
|
|
476
|
+
# print('result', result)
|
|
477
|
+
for i in result.items():
|
|
478
|
+
if directorys[i]:
|
|
479
|
+
server = {'directory': directorys[i]}
|
|
480
|
+
else:
|
|
481
|
+
server = {}
|
|
482
|
+
for j, line in enumerate(result[i]):
|
|
483
|
+
if j == 0:
|
|
484
|
+
server['ip'] = result[i][0]
|
|
485
|
+
elif j == 1:
|
|
486
|
+
server['port'] = result[i][1]
|
|
487
|
+
elif j == 2:
|
|
488
|
+
server['_inpanel'] = result[i][2]
|
|
489
|
+
elif j == 3:
|
|
490
|
+
server['disabled'] = result[i][3]
|
|
491
|
+
server['status'] = 'off' if result[i][3] else 'on'
|
|
492
|
+
else:
|
|
493
|
+
fields = line.split()
|
|
494
|
+
key = fields[0].lower()
|
|
495
|
+
if key == 'directoryindex':
|
|
496
|
+
server['directoryindex'] = ' '.join(str(n) for n in fields[1:])
|
|
497
|
+
elif key == 'serveralias':
|
|
498
|
+
server['serveralias'] = fields[1:]
|
|
499
|
+
elif key == 'customlog':
|
|
500
|
+
server['customlog'] = ' '.join(fields[1:])
|
|
501
|
+
elif key in ('serveradmin', 'servername', 'documentroot', 'errorlog', 'options', 'location', 'suexecusergroup'):
|
|
502
|
+
server[key] = fields[1].strip(' ').strip('"')
|
|
503
|
+
|
|
504
|
+
configs['virtualhost'].append(server)
|
|
505
|
+
|
|
506
|
+
# configs['gzip'] = _context_check_gzip(LoadModule, IfModule)
|
|
507
|
+
return configs
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def _parse_directory(directory):
|
|
511
|
+
'''read and detect directory config
|
|
512
|
+
'''
|
|
513
|
+
if not directory:
|
|
514
|
+
return []
|
|
515
|
+
|
|
516
|
+
results = []
|
|
517
|
+
for r in directory:
|
|
518
|
+
drct = {
|
|
519
|
+
'path': '',
|
|
520
|
+
'allow': [],
|
|
521
|
+
'deny': []
|
|
522
|
+
}
|
|
523
|
+
for line in r:
|
|
524
|
+
line = line.split()
|
|
525
|
+
key = line[0].lower()
|
|
526
|
+
if key == 'path':
|
|
527
|
+
drct['path'] = line[1].strip()
|
|
528
|
+
elif key == 'order':
|
|
529
|
+
drct['order'] = (','.join(str(n) for n in line[1:])).lower()
|
|
530
|
+
elif key in ('allow', 'deny'):
|
|
531
|
+
# drct[key].append(line[2].strip()) # only multi-line IPs
|
|
532
|
+
drct[key].extend([i for i in line[2:]]) # support multi-line IPs and multiple IPs per line
|
|
533
|
+
elif key in ('allowoverride'):
|
|
534
|
+
drct[key] = line[1].strip()
|
|
535
|
+
elif key == 'options':
|
|
536
|
+
options = (' '.join(str(n) for n in line[1:])).lower()
|
|
537
|
+
if '-indexes' in options:
|
|
538
|
+
drct['indexes'] = '-'
|
|
539
|
+
elif 'indexes' in options or '+indexes' in options:
|
|
540
|
+
drct['indexes'] = '+'
|
|
541
|
+
if '-followsymlinks' in options:
|
|
542
|
+
drct['followsymlinks'] = '-'
|
|
543
|
+
elif 'followsymlinks' in options or '+followsymlinks' in options:
|
|
544
|
+
drct['followsymlinks'] = '+'
|
|
545
|
+
if '-execcgi' in options:
|
|
546
|
+
drct['execcgi'] = '-'
|
|
547
|
+
elif 'execcgi' in options or '+execcgi' in options:
|
|
548
|
+
drct['execcgi'] = '+'
|
|
549
|
+
order = drct.get('order', '')
|
|
550
|
+
if order in ('allow,deny', 'deny,allow'):
|
|
551
|
+
drct['allow_enable'] = True
|
|
552
|
+
drct['deny_enable'] = True
|
|
553
|
+
results.append(drct)
|
|
554
|
+
# print(results)
|
|
555
|
+
return results
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def getservers(config=None):
|
|
559
|
+
'''Get servers from apache configuration files.
|
|
560
|
+
'''
|
|
561
|
+
if not config:
|
|
562
|
+
config = loadconfig()
|
|
563
|
+
return _context_getservers(config=config)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def getserver(ip, port, server_name, config=None):
|
|
567
|
+
'''Get server setting from Apache configuration files.
|
|
568
|
+
'''
|
|
569
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
570
|
+
config = loadconfig()
|
|
571
|
+
server = _context_getserver(ip, port, server_name, config=config)
|
|
572
|
+
return server[0] if len(server) >= 1 else None
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def virtual_host_config(site, key, val, port=80):
|
|
576
|
+
'''
|
|
577
|
+
site: abc.com
|
|
578
|
+
key: VirtualHost or DocumentRoot or ServerAdmin or Directory
|
|
579
|
+
val: /var/www
|
|
580
|
+
'''
|
|
581
|
+
keys = ['VirtualHost', 'DocumentRoot', 'ServerAdmin', 'Directory']
|
|
582
|
+
if key not in keys or not site or not val:
|
|
583
|
+
return False
|
|
584
|
+
|
|
585
|
+
conf = SERVERCONF + site + '.conf'
|
|
586
|
+
try:
|
|
587
|
+
stat(conf)
|
|
588
|
+
except OSError:
|
|
589
|
+
print('site config file not exist')
|
|
590
|
+
return False
|
|
591
|
+
|
|
592
|
+
old_conf = open(conf, encoding='utf-8').read()
|
|
593
|
+
|
|
594
|
+
with open(conf + '.bak', 'w', encoding='utf-8') as f:
|
|
595
|
+
# backup
|
|
596
|
+
f.write(old_conf)
|
|
597
|
+
|
|
598
|
+
if key == 'VirtualHost':
|
|
599
|
+
conf = SERVERCONF + val + '.conf'
|
|
600
|
+
val = str(val) + ':' + str(port)
|
|
601
|
+
# os.renames(SERVERCONF + site + '.conf', conf + '.bak')
|
|
602
|
+
|
|
603
|
+
# make new config
|
|
604
|
+
new_conf = re.sub(key + ' "(.*?)"',
|
|
605
|
+
key + ' "' + val + '"',
|
|
606
|
+
old_conf)
|
|
607
|
+
|
|
608
|
+
# save new config file
|
|
609
|
+
with open(conf, 'w', encoding='utf-8') as f:
|
|
610
|
+
f.write(new_conf)
|
|
611
|
+
# delete old site config file
|
|
612
|
+
if key == 'VirtualHost' and stat(conf) and stat(SERVERCONF + site + '.conf.bak'):
|
|
613
|
+
remove(SERVERCONF + site + '.conf')
|
|
614
|
+
return True
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
# https://blog.csdn.net/brucemj/article/details/37933519
|
|
618
|
+
# https://oomake.com/question/266681
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def replace_docroot(vhost, new_docroot):
|
|
622
|
+
'''yield new lines of an httpd.conf file where docroot lines matching
|
|
623
|
+
the specified vhost are replaced with the new_docroot
|
|
624
|
+
'''
|
|
625
|
+
vhost_start = re.compile(r'<VirtualHost\s+(.*?)>')
|
|
626
|
+
vhost_end = re.compile(r'</VirtualHost>')
|
|
627
|
+
docroot_re = re.compile(r'(DocumentRoot\s+)(\S+)')
|
|
628
|
+
file = open(HTTPDCONF + vhost + '.conf', encoding='utf-8').read()
|
|
629
|
+
conf_file = StringIO(file)
|
|
630
|
+
in_vhost = False
|
|
631
|
+
curr_vhost = None
|
|
632
|
+
for line in conf_file:
|
|
633
|
+
# 起始行查找host
|
|
634
|
+
vhost_start_match = vhost_start.search(line)
|
|
635
|
+
if vhost_start_match:
|
|
636
|
+
curr_vhost = vhost_start_match.groups()[0]
|
|
637
|
+
in_vhost = True
|
|
638
|
+
print(curr_vhost, vhost)
|
|
639
|
+
if in_vhost and (curr_vhost == vhost):
|
|
640
|
+
docroot_match = docroot_re.search(line)
|
|
641
|
+
if docroot_match:
|
|
642
|
+
sub_line = docroot_re.sub(r'\1%s' % new_docroot, line)
|
|
643
|
+
line = sub_line
|
|
644
|
+
vhost_end_match = vhost_end.search(line)
|
|
645
|
+
if vhost_end_match:
|
|
646
|
+
in_vhost = False
|
|
647
|
+
yield line
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def _context_check_gzip(LoadModule, IfModule):
|
|
651
|
+
mod_status = (
|
|
652
|
+
['ext_filter_module', 'modules/mod_ext_filter.so'] in LoadModule and
|
|
653
|
+
['deflate_module', 'modules/mod_deflate.so'] in LoadModule and
|
|
654
|
+
['headers_module', 'modules/mod_headers.so'] in LoadModule
|
|
655
|
+
)
|
|
656
|
+
# check deflate config in IfModule
|
|
657
|
+
mod_deflate = True
|
|
658
|
+
return mod_status and mod_deflate
|
|
659
|
+
|
|
660
|
+
def _context_gethttp(config=None):
|
|
661
|
+
"""Get http context config.
|
|
662
|
+
"""
|
|
663
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
664
|
+
config = loadconfig(APACHECONF, True)
|
|
665
|
+
print('config', config)
|
|
666
|
+
return config['_'][0]
|
|
667
|
+
|
|
668
|
+
def _context_getservers(disabled=None, config=None, getlineinfo=True):
|
|
669
|
+
'''Get server context configs.
|
|
670
|
+
'''
|
|
671
|
+
|
|
672
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
673
|
+
config = loadconfig(APACHECONF, getlineinfo)
|
|
674
|
+
servers = []
|
|
675
|
+
if 'virtualhost' in config and len(config['virtualhost']) > 0:
|
|
676
|
+
servers = config['virtualhost']
|
|
677
|
+
if disabled == None or not getlineinfo:
|
|
678
|
+
return servers
|
|
679
|
+
else:
|
|
680
|
+
return [server for server in servers if server['disabled'] == disabled]
|
|
681
|
+
|
|
682
|
+
def _context_getserver(ip, port, servername, config=None, disabled=None, getlineinfo=True):
|
|
683
|
+
'''Get a server context config by ip:port and servername.
|
|
684
|
+
|
|
685
|
+
If disabled is None, return all servers
|
|
686
|
+
If disabled is True, return only disabled servers
|
|
687
|
+
If disabled is False, return only normal servers
|
|
688
|
+
'''
|
|
689
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
690
|
+
config = loadconfig(APACHECONF, getlineinfo)
|
|
691
|
+
cnfservers = _context_getservers(disabled=disabled, config=config, getlineinfo=getlineinfo)
|
|
692
|
+
# print(cnfservers)
|
|
693
|
+
if not ip or ip in ('*', '0.0.0.0'):
|
|
694
|
+
ip = '*'
|
|
695
|
+
if is_valid_ipv6(ip) and not is_valid_ipv4(ip):
|
|
696
|
+
ip = '[' + ip + ']'
|
|
697
|
+
port = str(port)
|
|
698
|
+
return [s for s in cnfservers if ip == s['ip'] and port == s['port'] and s['servername'] == servername or 'serveralias' in s and servername in s['serveralias']]
|
|
699
|
+
# if getlineinfo:
|
|
700
|
+
# s_names = ' '.join([v['value'] for v in s['server_name']]).split()
|
|
701
|
+
# listens = [v['value'].split()[0] for v in s['listen']]
|
|
702
|
+
# else:
|
|
703
|
+
# s_names = ' '.join([v for v in s['server_name']]).split()
|
|
704
|
+
# listens = [v.split()[0] for v in s['listen']]
|
|
705
|
+
# find_listen = ip and ['%s:%s' % (ip, port)] or [port, '*:%s' % port, '0.0.0.0:%s' % port]
|
|
706
|
+
# if server_name == s_names and ip == s_ip and port == s_port: # any([i in listens for i in find_listen]):
|
|
707
|
+
# return s
|
|
708
|
+
# return False
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def _context_getupstreams(server_name, config=None, disabled=None, getlineinfo=True):
|
|
712
|
+
"""Get upstream list related to a server.
|
|
713
|
+
"""
|
|
714
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
715
|
+
config = loadconfig(APACHECONF, getlineinfo)
|
|
716
|
+
upstreams = http_get('upstream', config)
|
|
717
|
+
if not upstreams: return False
|
|
718
|
+
if getlineinfo:
|
|
719
|
+
upstreams = [upstream for upstream in upstreams
|
|
720
|
+
if upstream['_param']['value'].startswith('backend_of_%s_' % server_name)]
|
|
721
|
+
else:
|
|
722
|
+
upstreams = [upstream for upstream in upstreams
|
|
723
|
+
if upstream['_param'].startswith('backend_of_%s_' % server_name)]
|
|
724
|
+
|
|
725
|
+
if disabled == None or not getlineinfo:
|
|
726
|
+
return upstreams
|
|
727
|
+
else:
|
|
728
|
+
return [upstream for upstream in upstreams
|
|
729
|
+
if upstream['_param']['disabled']==disabled]
|
|
730
|
+
|
|
731
|
+
def _comment(filepath, start, end):
|
|
732
|
+
"""Commend some lines in the file.
|
|
733
|
+
"""
|
|
734
|
+
if not Path(filepath).is_file():
|
|
735
|
+
return False
|
|
736
|
+
data = []
|
|
737
|
+
with open(filepath, encoding='utf-8') as f:
|
|
738
|
+
for i, line in enumerate(f):
|
|
739
|
+
if i >= start and i <= end:
|
|
740
|
+
if not line.startswith(COMMENTFLAG):
|
|
741
|
+
data.append(COMMENTFLAG)
|
|
742
|
+
data.append(line)
|
|
743
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
744
|
+
f.write(''.join(data))
|
|
745
|
+
return True
|
|
746
|
+
|
|
747
|
+
def _uncomment(filepath, start, end):
|
|
748
|
+
"""Uncommend some lines in the file.
|
|
749
|
+
"""
|
|
750
|
+
if not Path(filepath).is_file():
|
|
751
|
+
return False
|
|
752
|
+
data = []
|
|
753
|
+
with open(filepath, encoding='utf-8') as f:
|
|
754
|
+
for i, line in enumerate(f):
|
|
755
|
+
if i >= start and i <= end:
|
|
756
|
+
while line.startswith(COMMENTFLAG):
|
|
757
|
+
line = line[3:]
|
|
758
|
+
data.append(line)
|
|
759
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
760
|
+
f.write(''.join(data))
|
|
761
|
+
return True
|
|
762
|
+
|
|
763
|
+
def _delete(filepath, start, end, delete_emptyfile=True):
|
|
764
|
+
"""Delete some lines in the file.
|
|
765
|
+
|
|
766
|
+
If delete_emptyfile is set to True, then the empty file will
|
|
767
|
+
be deleted from file system.
|
|
768
|
+
"""
|
|
769
|
+
if not Path(filepath).is_file():
|
|
770
|
+
return False
|
|
771
|
+
data = []
|
|
772
|
+
with open(filepath, encoding='utf-8') as f:
|
|
773
|
+
for i, line in enumerate(f):
|
|
774
|
+
if i >= start and i <= end:
|
|
775
|
+
continue
|
|
776
|
+
data.append(line)
|
|
777
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
778
|
+
f.write(''.join(data))
|
|
779
|
+
if delete_emptyfile:
|
|
780
|
+
if ''.join(data).strip() == '':
|
|
781
|
+
unlink(filepath)
|
|
782
|
+
return True
|
|
783
|
+
|
|
784
|
+
def _getcontextrange(context, config):
|
|
785
|
+
"""Return the range of the input context, including the file path.
|
|
786
|
+
|
|
787
|
+
Return format:
|
|
788
|
+
[filepath, line_start, line_end]
|
|
789
|
+
"""
|
|
790
|
+
file_i = context['_range']['begin']['file']
|
|
791
|
+
filepath = config['_files'][file_i]
|
|
792
|
+
line_start = context['_range']['begin']['line'][0]
|
|
793
|
+
line_end = context['_range']['end']['line'][0]
|
|
794
|
+
return [filepath, line_start, line_end]
|
|
795
|
+
|
|
796
|
+
def _context_commentserver(ip, port, server_name, config=None):
|
|
797
|
+
"""Comment a context using InPanel's special comment string '#v#'
|
|
798
|
+
"""
|
|
799
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
800
|
+
config = loadconfig(APACHECONF, True)
|
|
801
|
+
scontext = _context_getserver(ip, port, server_name, config=config)
|
|
802
|
+
if not scontext: return False
|
|
803
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
804
|
+
return _comment(filepath, line_start, line_end)
|
|
805
|
+
|
|
806
|
+
def _context_uncommentserver(ip, port, server_name, config=None):
|
|
807
|
+
"""Uncomment a InPanel's special-commented context.
|
|
808
|
+
"""
|
|
809
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
810
|
+
config = loadconfig(APACHECONF, True)
|
|
811
|
+
scontext = _context_getserver(ip, port, server_name, config=config)
|
|
812
|
+
if not scontext: return False
|
|
813
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
814
|
+
return _uncomment(filepath, line_start, line_end)
|
|
815
|
+
|
|
816
|
+
def _context_deleteserver(ip, port, server_name, config=None, disabled=None):
|
|
817
|
+
"""Delete a server context.
|
|
818
|
+
"""
|
|
819
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
820
|
+
config = loadconfig(APACHECONF, True)
|
|
821
|
+
scontext = _context_getserver(ip, port, server_name, config=config, disabled=disabled)
|
|
822
|
+
if not scontext: return False
|
|
823
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
824
|
+
config['_isdirty'] = True
|
|
825
|
+
return _delete(filepath, line_start, line_end)
|
|
826
|
+
|
|
827
|
+
def _context_commentupstreams(server_name, config=None):
|
|
828
|
+
"""Comment upstreams by server names.
|
|
829
|
+
"""
|
|
830
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
831
|
+
config = loadconfig(APACHECONF, True)
|
|
832
|
+
upstreams = _context_getupstreams(server_name, config=config)
|
|
833
|
+
if not upstreams: return True
|
|
834
|
+
for upstream in upstreams:
|
|
835
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
836
|
+
if not _comment(filepath, line_start, line_end): return False
|
|
837
|
+
return True
|
|
838
|
+
|
|
839
|
+
def _context_uncommentupstreams(server_name, config=None):
|
|
840
|
+
"""Uncomment upstreams by server names.
|
|
841
|
+
"""
|
|
842
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
843
|
+
config = loadconfig(APACHECONF, True)
|
|
844
|
+
upstreams = _context_getupstreams(server_name, config=config)
|
|
845
|
+
if not upstreams: return True
|
|
846
|
+
for upstream in upstreams:
|
|
847
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
848
|
+
if not _uncomment(filepath, line_start, line_end): return False
|
|
849
|
+
return True
|
|
850
|
+
|
|
851
|
+
def _context_deleteupstreams(server_name, config=None, disabled=None):
|
|
852
|
+
"""Delete upstreams by server name.
|
|
853
|
+
"""
|
|
854
|
+
while True:
|
|
855
|
+
# we need to reload config after delete one upstream
|
|
856
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
857
|
+
config = loadconfig(APACHECONF, True)
|
|
858
|
+
upstreams = _context_getupstreams(server_name, config=config, disabled=disabled)
|
|
859
|
+
if not upstreams: return True
|
|
860
|
+
for upstream in upstreams:
|
|
861
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
862
|
+
config['_isdirty'] = True
|
|
863
|
+
if not _delete(filepath, line_start, line_end): return False
|
|
864
|
+
break # only delete the first one
|
|
865
|
+
return True
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def _replace(positions, lines):
|
|
869
|
+
"""Replace the lines specified in list positions to new lines.
|
|
870
|
+
|
|
871
|
+
Structure of positions:
|
|
872
|
+
[
|
|
873
|
+
(filepath, line_start, line_count),
|
|
874
|
+
...
|
|
875
|
+
]
|
|
876
|
+
Parameter positions can not be empty.
|
|
877
|
+
|
|
878
|
+
* If the new lines is empty, old lines with be deleted.
|
|
879
|
+
* If the new lines is less than the old lines, the rest old lines
|
|
880
|
+
will also be deleted.
|
|
881
|
+
* If the new lines is more than the old lines, then new value will
|
|
882
|
+
append after the last line of the old lines.
|
|
883
|
+
"""
|
|
884
|
+
# merge line positions by filepath
|
|
885
|
+
# struct: {'/path/to/file': [3, 4, 10, ...], ...}
|
|
886
|
+
files = {}
|
|
887
|
+
for pos in positions:
|
|
888
|
+
filepath, line_start, line_count = pos
|
|
889
|
+
if not filepath in files:
|
|
890
|
+
files[filepath] = []
|
|
891
|
+
for i in range(line_count):
|
|
892
|
+
files[filepath].append(line_start+i)
|
|
893
|
+
# replace line by line
|
|
894
|
+
for filepath, line_nums in files.items():
|
|
895
|
+
flines = []
|
|
896
|
+
with open(filepath, encoding='utf-8') as f:
|
|
897
|
+
for i, fline in enumerate(f):
|
|
898
|
+
if i in line_nums:
|
|
899
|
+
if len(lines) > 0:
|
|
900
|
+
# replace with a new line
|
|
901
|
+
line = lines[0]
|
|
902
|
+
lines = lines[1:]
|
|
903
|
+
# detect the space at the start of the old line
|
|
904
|
+
# this aim to keep the indent of the line
|
|
905
|
+
space = ''
|
|
906
|
+
for c in fline:
|
|
907
|
+
if c not in (' ', '\t'):
|
|
908
|
+
break
|
|
909
|
+
space += c
|
|
910
|
+
flines.append(''.join([space, line, '\n']))
|
|
911
|
+
else:
|
|
912
|
+
# no more new line, delete the old line
|
|
913
|
+
continue
|
|
914
|
+
else:
|
|
915
|
+
if i > line_nums[-1] and len(lines) > 0:
|
|
916
|
+
# exceed the last old line, insert the rest new lines here
|
|
917
|
+
# detect the indent of the last line
|
|
918
|
+
space = ''
|
|
919
|
+
if len(flines)>0: # last line exists
|
|
920
|
+
for c in flines[-1]:
|
|
921
|
+
if c not in (' ', '\t'):
|
|
922
|
+
break
|
|
923
|
+
space += c
|
|
924
|
+
for line in lines:
|
|
925
|
+
flines.append(''.join([space, line, '\n']))
|
|
926
|
+
lines = []
|
|
927
|
+
flines.append(fline)
|
|
928
|
+
# write back to file
|
|
929
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
930
|
+
f.write(''.join(flines))
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
def _insert(filepath, line_start, lines):
|
|
934
|
+
"""Insert the lines to the specified position.
|
|
935
|
+
"""
|
|
936
|
+
flines = []
|
|
937
|
+
with open(filepath, encoding='utf-8') as f:
|
|
938
|
+
for i, fline in enumerate(f):
|
|
939
|
+
if i == line_start:
|
|
940
|
+
# detect the indent of the last not empty line
|
|
941
|
+
space = ''
|
|
942
|
+
flines_len = len(flines)
|
|
943
|
+
if flines_len>0: # last line exists
|
|
944
|
+
line_i = -1
|
|
945
|
+
while flines[line_i].strip() == '' and -line_i <= flines_len:
|
|
946
|
+
line_i -= 1
|
|
947
|
+
for c in flines[line_i]:
|
|
948
|
+
if c not in (' ', '\t'):
|
|
949
|
+
break
|
|
950
|
+
space += c
|
|
951
|
+
if flines[line_i].strip().endswith('{'):
|
|
952
|
+
space += ' '
|
|
953
|
+
for line in lines:
|
|
954
|
+
flines.append(''.join([space, line, '\n']))
|
|
955
|
+
flines.append(fline)
|
|
956
|
+
# write back to file
|
|
957
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
958
|
+
f.write(''.join(flines))
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
def http_get(directive, config=None):
|
|
962
|
+
"""Get directive values in http context.
|
|
963
|
+
"""
|
|
964
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
965
|
+
config = loadconfig(APACHECONF)
|
|
966
|
+
hcontext = _context_gethttp(config)
|
|
967
|
+
if directive in hcontext:
|
|
968
|
+
return hcontext[directive]
|
|
969
|
+
else:
|
|
970
|
+
return None
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
def http_getfirst(directive, config=None):
|
|
974
|
+
"""Get the first value of the directive in http context.
|
|
975
|
+
"""
|
|
976
|
+
values = http_get(directive, config)
|
|
977
|
+
if values:
|
|
978
|
+
return values[0]
|
|
979
|
+
return None
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def http_set(directive, values, config=None):
|
|
983
|
+
"""Set a directive in http context.
|
|
984
|
+
|
|
985
|
+
If directive exists, the value will be replace in place.
|
|
986
|
+
If directive not exists, new directive will be created at the beginning of http context.
|
|
987
|
+
|
|
988
|
+
Parameter values can be a list or a string.
|
|
989
|
+
If values is set to empty list or None or empty string, then the directive will be deleted.
|
|
990
|
+
"""
|
|
991
|
+
if config is None or ('_isdirty' in config and config['_isdirty']):
|
|
992
|
+
config = loadconfig(APACHECONF, True)
|
|
993
|
+
hcontext = _context_gethttp(config)
|
|
994
|
+
|
|
995
|
+
if not values:
|
|
996
|
+
values = []
|
|
997
|
+
elif isinstance(values, str):
|
|
998
|
+
values = [values]
|
|
999
|
+
values = ['%s %s;' % (directive, v) for v in values]
|
|
1000
|
+
|
|
1001
|
+
if directive in hcontext:
|
|
1002
|
+
# update or delete value
|
|
1003
|
+
dvalues = hcontext[directive]
|
|
1004
|
+
lines = [(config['_files'][dvalue['file']], dvalue['line'][0], dvalue['line'][1]) for dvalue in dvalues]
|
|
1005
|
+
_replace(lines, values)
|
|
1006
|
+
else:
|
|
1007
|
+
# add directive to the beginning of http context
|
|
1008
|
+
# some directive like proxy_cache_path should be declare before use the resource,
|
|
1009
|
+
# so we should insert it at the beginning
|
|
1010
|
+
begin = hcontext['_range']['begin']
|
|
1011
|
+
_insert(config['_files'][begin['file']], begin['line'][0]+begin['line'][1], values)
|
|
1012
|
+
|
|
1013
|
+
config['_isdirty'] = True
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
def disableserver(ip, port, servername):
|
|
1017
|
+
"""Disable a server.
|
|
1018
|
+
"""
|
|
1019
|
+
_context_commentupstreams(servername)
|
|
1020
|
+
return _context_commentserver(ip, port, servername)
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
def enableserver(ip, port, servername):
|
|
1024
|
+
"""Enable a server.
|
|
1025
|
+
"""
|
|
1026
|
+
_context_uncommentupstreams(servername)
|
|
1027
|
+
return _context_uncommentserver(ip, port, servername)
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
def deleteserver(server_name, ip, port):
|
|
1031
|
+
'''Delete a server.'''
|
|
1032
|
+
print(SERVERCONF + server_name + '.conf')
|
|
1033
|
+
try:
|
|
1034
|
+
unlink(SERVERCONF + server_name + '.conf')
|
|
1035
|
+
return True
|
|
1036
|
+
except:
|
|
1037
|
+
return False
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
def servername_exists(ip, port, server_name, config=None):
|
|
1041
|
+
'''Check if the server_name at given ip:port is already exists.
|
|
1042
|
+
'''
|
|
1043
|
+
return _context_getserver(ip, port, server_name, config=config) and True or False
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
def addserver(serveraname, ip, port, serveralias=None, serveradmin=None, documentroot=None, directoryindex=None, directory=None, errorlog=None, customlog=None, version=None):
|
|
1047
|
+
'''Add a new VirtualHost.'''
|
|
1048
|
+
if not is_valid_domain(serveraname):
|
|
1049
|
+
return False
|
|
1050
|
+
ip = ip or '*'
|
|
1051
|
+
if is_valid_ipv6(ip) and not is_valid_ipv4(ip):
|
|
1052
|
+
ip = '[' + ip + ']'
|
|
1053
|
+
if port:
|
|
1054
|
+
port = str(port) or '80'
|
|
1055
|
+
else:
|
|
1056
|
+
return False
|
|
1057
|
+
if not documentroot:
|
|
1058
|
+
return False
|
|
1059
|
+
# check if any of servername - ip - port pair already exists
|
|
1060
|
+
if servername_exists(ip, port, serveraname):
|
|
1061
|
+
return False
|
|
1062
|
+
|
|
1063
|
+
# start generate the config string
|
|
1064
|
+
servercfg = [f'<VirtualHost {ip}:{port}> # {GENBY}']
|
|
1065
|
+
servercfg.append(f' ServerName {serveraname}')
|
|
1066
|
+
servercfg.append(f' DocumentRoot {documentroot}')
|
|
1067
|
+
if serveradmin:
|
|
1068
|
+
servercfg.append(f' ServerAdmin {serveradmin}')
|
|
1069
|
+
if serveralias:
|
|
1070
|
+
servercfg.append(f' ServerAlias {" ".join(serveralias)}')
|
|
1071
|
+
if directoryindex:
|
|
1072
|
+
servercfg.append(f' DirectoryIndex {" ".join(directoryindex.split())}')
|
|
1073
|
+
else:
|
|
1074
|
+
servercfg.append(' DirectoryIndex index.html index.htm index.php')
|
|
1075
|
+
if errorlog:
|
|
1076
|
+
servercfg.append(f' ErrorLog {errorlog}')
|
|
1077
|
+
if customlog:
|
|
1078
|
+
servercfg.append(f' CustomLog {customlog}')
|
|
1079
|
+
if directory and len(directory) > 0:
|
|
1080
|
+
d = _extend_directory(directory)
|
|
1081
|
+
servercfg.extend([' %s' % i for i in d])
|
|
1082
|
+
# end of server context
|
|
1083
|
+
servercfg.append('</VirtualHost>')
|
|
1084
|
+
|
|
1085
|
+
#print '\n'.join(servercfg)
|
|
1086
|
+
configfile = str(Path(SERVERCONF) / (serveraname + '.conf'))
|
|
1087
|
+
configfile_exists = Path(configfile).exists()
|
|
1088
|
+
|
|
1089
|
+
# check if need to add a new line at the end of the file to
|
|
1090
|
+
# avoid first line go to the same former } line
|
|
1091
|
+
if configfile_exists:
|
|
1092
|
+
with open(configfile, encoding='utf-8') as f:
|
|
1093
|
+
f.seek(-1, 2)
|
|
1094
|
+
if f.read(1) != '\n':
|
|
1095
|
+
servercfg.insert(0, '')
|
|
1096
|
+
with open(configfile, configfile_exists and 'a' or 'w', encoding='utf-8') as f:
|
|
1097
|
+
f.write('\n'.join(servercfg))
|
|
1098
|
+
return True
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def _extend_directory(directory):
|
|
1102
|
+
'''extend Directory config to line for build configfile.
|
|
1103
|
+
Usage
|
|
1104
|
+
----------
|
|
1105
|
+
> d = _extend_directory(directory)\n
|
|
1106
|
+
> servercfg.extend(d) # for Apache Config\n
|
|
1107
|
+
> servercfg.extend([' %s' % i for i in d]) # for VirtualHost Config
|
|
1108
|
+
'''
|
|
1109
|
+
drct_cfg = []
|
|
1110
|
+
for drct in directory:
|
|
1111
|
+
if 'path' in drct and drct['path']:
|
|
1112
|
+
drct_cfg.append('<Directory %s>' % drct['path'])
|
|
1113
|
+
else:
|
|
1114
|
+
continue
|
|
1115
|
+
options = []
|
|
1116
|
+
if drct.get('indexes'): # '+' or '-'
|
|
1117
|
+
options.append(str(drct['indexes']) + 'indexes')
|
|
1118
|
+
if drct.get('followsymlinks'):
|
|
1119
|
+
options.append(str(drct['followsymlinks']) + 'followsymlinks')
|
|
1120
|
+
if drct.get('execcgi'):
|
|
1121
|
+
options.append(str(drct['execcgi']) + 'execcgi')
|
|
1122
|
+
if len(options) > 0:
|
|
1123
|
+
drct_cfg.append(' Options ' + ' '.join(options))
|
|
1124
|
+
if drct.get('order'):
|
|
1125
|
+
drct_cfg.append(' Order ' + drct['order'])
|
|
1126
|
+
if len(drct.get('allow', [])) > 0:
|
|
1127
|
+
drct_cfg.extend([' allow from %s' % i for i in drct['allow']])
|
|
1128
|
+
if len(drct.get('deny', [])) > 0:
|
|
1129
|
+
drct_cfg.extend([' deny from %s' % i for i in drct['deny']])
|
|
1130
|
+
drct_cfg.append('</Directory>')
|
|
1131
|
+
return drct_cfg
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
def updateserver(old_name, old_ip, old_port, serveraname, ip, port, serveralias=None, serveradmin=None, documentroot=None, directoryindex=None, directory=None, errorlog=None, customlog=None, version=None):
|
|
1135
|
+
'''Update an existing server.
|
|
1136
|
+
|
|
1137
|
+
If the old config is not in the right place, we would automatically delete it and
|
|
1138
|
+
create the new config to coresponding config file under /etc/httpd/conf.d/.
|
|
1139
|
+
'''
|
|
1140
|
+
# compare the old context and the new context
|
|
1141
|
+
# to check if the ip:port/server_name change and conflict status
|
|
1142
|
+
config = loadconfig(APACHECONF, True)
|
|
1143
|
+
oldscontext = _context_getserver(old_ip, old_port, old_name, config)
|
|
1144
|
+
if not oldscontext:
|
|
1145
|
+
return False
|
|
1146
|
+
scontext = _context_getserver(ip, port, serveraname)
|
|
1147
|
+
# server context found, but not equals to the old
|
|
1148
|
+
# this means conflict occur
|
|
1149
|
+
if scontext and scontext != oldscontext:
|
|
1150
|
+
return False
|
|
1151
|
+
|
|
1152
|
+
if __name__ == '__main__':
|
|
1153
|
+
HTTPDCONF = '/Users/douzhenjiang/Projects/inpanel/test'
|
|
1154
|
+
APACHECONF = '/Users/douzhenjiang/Projects/inpanel/test/httpd.conf'
|
|
1155
|
+
SERVERCONF = '/Users/douzhenjiang/Projects/inpanel/test/conf.d/'
|
|
1156
|
+
print(locals())
|
|
1157
|
+
# tmp = loadconfig()
|
|
1158
|
+
# print('config', tmp)
|
|
1159
|
+
# print(dumps(tmp))
|
|
1160
|
+
# virtual_host_config('aaa.com', 'DocumentRoot', '/v/asfs34535')
|
|
1161
|
+
# virtual_host_config('aaa.com', 'ServerAdmin', '4567896543')
|
|
1162
|
+
# virtual_host_config('aaa.com', 'VirtualHost', 'bbb.com', 567)
|
|
1163
|
+
|
|
1164
|
+
# for line in replace_docroot('aaa.com', 'docroot'):
|
|
1165
|
+
# print(line)
|
|
1166
|
+
|
|
1167
|
+
# aaa = '/Users/douzhenjiang/Projects/inpanel/test/aaa.com.conf'
|
|
1168
|
+
# tmp1 = loadconfig()
|
|
1169
|
+
# print(dumps(tmp1))
|
|
1170
|
+
# s= tmp1['virtualhost']
|
|
1171
|
+
# # s = scontext['virtualhost']
|
|
1172
|
+
# s= [i for i in s if i['port']=='870' and i['ip']=='1.1.1.1' and i['servername']=='inpanel.org']
|
|
1173
|
+
# print(s)
|
|
1174
|
+
# s = getserver('1.1.1.1', '80', 'aaaaaaaa.aa')
|
|
1175
|
+
# s = servername_exists('1.1.1.1', 80, 'aaaaaaaa.aa')
|
|
1176
|
+
# print(s)
|
|
1177
|
+
# s = addserver('aaaaaaaa.aa', '1.1.1.1', 801, documentroot='/Users/douzhenjiang/Projects/inpanel/test')
|
|
1178
|
+
# s = getserver('1.1.1.1', 80, 'aaaaaaaa.aa')
|
|
1179
|
+
# s = dumps(s)
|
|
1180
|
+
# print(s)
|
|
1181
|
+
# for i in s:
|
|
1182
|
+
# print('port' in i)
|
|
1183
|
+
# # if i.port=='80':
|
|
1184
|
+
# # print(i)
|
|
1185
|
+
# # break
|
|
1186
|
+
# print([i for i in s if i['port']=='870' and i['ip']=='1.1.1.1' and i['servername']=='inpanel.org'])
|
|
1187
|
+
|
|
1188
|
+
# print dumps(_context_getservers(disabled=None))
|
|
1189
|
+
|
|
1190
|
+
# path = str(Path(SERVERCONF, clist[i])
|
|
1191
|
+
# print os.path.splitext('/Users/douzhenjiang/Projects/inpanel/test/aaa.com')
|
|
1192
|
+
# SERVERCONF = '/Users/douzhenjiang/Projects/inpanel/test'
|
|
1193
|
+
# print(servername_exists('1.1.1.1', 80, 'inpanel.org'))
|
|
1194
|
+
# addserver('inpanel.org', '1.1.1.1', 80,
|
|
1195
|
+
# serveralias=['cc.com', 'bb.com'],
|
|
1196
|
+
# serveradmin='root',
|
|
1197
|
+
# documentroot='/var/www/inpanel.org',
|
|
1198
|
+
# directoryindex='index.html index.php',
|
|
1199
|
+
# directory=[{'path': '/var/www/inpanel.org/abc',
|
|
1200
|
+
# 'options': 'aadsfsdf asdfdsf'}],
|
|
1201
|
+
# errorlog='abc/aaa.log',
|
|
1202
|
+
# customlog='abc/aaa_error.log',
|
|
1203
|
+
# version=None)
|
|
1204
|
+
# print(enableserver('*', 80, 'zhoukan.pub'))
|
|
1205
|
+
|