Files
2026-05-18 14:16:07 +08:00

5733 lines
255 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# coding: utf-8
# -------------------------------------------------------------------
# aapanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 aapanel Software(https://aapanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: lkq <lkq@bt.cn>
# -------------------------------------------------------------------
# ------------------------------
# Java model
# ------------------------------
import os, sys, re, json, shutil, psutil, time
import datetime
import pwd
from projectModelV2.base import projectBase
from projectModelV2.watchModel import use_project_watch, add_project_watch, del_project_watch
import public, firewalls
try:
from BTPanel import cache
except:
pass
from xml.etree.ElementTree import ElementTree, Element
class mobj:
port = ps = ''
class main(projectBase):
_panel_path = public.get_panel_path()
__bttomcat_path = '/usr/local/bttomcat'
__jdk_path = '/usr/lib/jvm/'
__btjdk_path = '/usr/local/btjdk/'
_log_name = 'project management'
__tomcat7_server = '/usr/local/bttomcat/tomcat7/conf/server.xml'
__tomcat8_server = '/usr/local/bttomcat/tomcat8/conf/server.xml'
__tomcat9_server = '/usr/local/bttomcat/tomcat9/conf/server.xml'
__tomcat7_path = '/usr/local/bttomcat/tomcat7'
__tomcat8_path = '/usr/local/bttomcat/tomcat8'
__tomcat9_path = '/usr/local/bttomcat/tomcat9'
__tomcat7_path_bak = '/usr/local/bttomcat/tomcat_bak7'
__tomcat8_path_bak = '/usr/local/bttomcat/tomcat_bak8'
__tomcat9_path_bak = '/usr/local/bttomcat/tomcat_bak9'
__site_path = '/www/server/bt_tomcat_web/'
_springboot = '/var/tmp/springboot'
_springboot_pid_path = '{}/vhost/pids'.format(_springboot)
_springboot_logs_path = '/www/wwwlogs/java/springboot'
_springboot_logs = '{}/vhost/logs'.format(_springboot)
_springboot_run_scripts = '{}/vhost/scripts'.format(_springboot)
__log_split_script_py = public.get_panel_path() + '/script/run_log_split.py'
_pids = None
__TREE = None
__ENGINE = None
__ROOT = None
__CONF_FILE = ''
__CONNECTROR = ''
_vhost_path = '{}/vhost'.format(_panel_path)
def __init__(self):
if not os.path.exists(self.__site_path):
os.makedirs(self.__site_path)
if not os.path.exists(self.__bttomcat_path):
os.makedirs(self.__bttomcat_path)
if not os.path.exists(self.__btjdk_path):
os.makedirs(self.__btjdk_path)
if not os.path.exists(self._springboot):
os.makedirs(self._springboot)
if not os.path.exists(self._springboot_pid_path):
os.makedirs(self._springboot_pid_path)
if not os.path.exists(self._springboot_logs_path):
os.makedirs(self._springboot_logs_path)
if not os.path.exists(self._springboot_logs):
os.makedirs(self._springboot_logs)
if not os.path.exists(self._springboot_run_scripts):
os.makedirs(self._springboot_run_scripts)
def test(self, get):
return type(get.domains)
def get_os_version(self, get):
"""
@name Get the installation command for the operating system version
@author lkq<2021-08-25>
@param get<dict_obj>
@return string
"""
# 获取Centos
if os.path.exists('/usr/bin/yum') and os.path.exists('/etc/yum.conf'):
return 'Centos'
# 获取Ubuntu
if os.path.exists('/usr/bin/apt-get') and os.path.exists('/usr/bin/dpkg'):
return 'Ubuntu'
return 'Unknown'
def get_jdk_version(self, get):
'''
@name Get JDK version
@author lkq<2021-08-25>
@param get<dict_obj>
@return string
'''
ret = []
ret2 = {}
if not 'JDK11' in ret2:
ret2['JDK11'] = {}
ret2['JDK11']['status'] = False
if not 'JDK8' in ret2:
ret2['JDK8'] = {}
ret2['JDK8']['status'] = False
if not os.path.exists(self.__jdk_path): return ret2
for root, dirs, files in os.walk(self.__jdk_path):
for i2 in dirs:
if not os.path.islink(self.__jdk_path + i2):
ret.append(self.__jdk_path + i2)
break
for i in ret:
if os.path.exists(i):
if 'java-1.8' in i or 'java-8' in i:
# Check if JDK is available
result = self.check_jdk(i)
java_ret = {}
if result:
java_ret['path'] = result
java_ret['status'] = True
java_ret['is_error'] = False
else:
java_ret['is_error'] = True
ret2['JDK8'] = java_ret
if 'java-11' in i or 'openjdk-11' in i:
result = self.check_jdk(i)
java_ret = {}
if result:
java_ret['path'] = i
java_ret['is_error'] = False
java_ret['status'] = True
else:
java_ret['is_error'] = True
ret2['JDK11'] = java_ret
return ret2
def install_jdk(self, get):
'''
@name Install JDK version
@author lkq<2021-08-25>
@param get<dict_obj>
@param get.jdk_version<string>
@return string
'''
tmp_file = '/tmp/panelShell.pl'
jdk_version = get.jdk_version.strip()
if jdk_version == '': return public.returnMsg(False, 'JDK version cannot be empty!')
jdk_list = ['8', '11']
if not jdk_version in jdk_list: return public.returnMsg(False, 'JDK version can only be 8 or 11!')
os_version = self.get_os_version(None)
if os_version == 'Centos':
if jdk_version == '8':
public.ExecShell('yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel -y >>%s' % tmp_file)
elif jdk_version == '11':
public.ExecShell('yum install java-11-openjdk java-11-openjdk-devel -y >>%s' % tmp_file)
else:
return public.returnMsg(False, 'JDK version can only be 8 or 11!')
# Check if JDK is available
jdk_data = self.get_jdk_version(None)
if jdk_data['JDK%s' % jdk_version]['status']:
# public.WriteFile(tmp_file,'Successify','a+')
return public.returnMsg(True, 'Installation successful!')
else:
public.WriteFile(tmp_file, 'Error: Please check if the yum source is normal', 'a+')
return public.returnMsg(False, 'Installation failed!')
elif os_version == 'Ubuntu':
if jdk_version == '8':
public.ExecShell('apt-get install -y openjdk-8-jre openjdk-8-jdk >>%s' % tmp_file)
elif jdk_version == '11':
public.ExecShell('apt-get install -y openjdk-11-jre openjdk-11-jdk >>%s' % tmp_file)
else:
return public.returnMsg(False, 'JDK version can only be 8 or 11!')
# Check if JDK is available
jdk_data = self.get_jdk_version(None)
if jdk_data['JDK%s' % jdk_version]['status']:
# public.WriteFile(tmp_file,'Successify','a+')
return public.returnMsg(True, 'Installation successful!')
else:
public.WriteFile(tmp_file, 'Error: Please check if the apt source is normal', 'a+')
return public.returnMsg(False, 'Installation failed!')
else:
public.WriteFile(tmp_file, 'Error: Unsupported operating system', 'a+')
return public.returnMsg(False, 'Operating system not supported!')
def remove_jdk(self, get):
'''
@name Remove JDK
@author lkq
@param get
@param get.jdk_version JDK version
@return
'''
jdk_version = get.jdk_version.strip()
os_version = self.get_os_version(None)
tmp_file = '/tmp/panelShell.pl'
if os_version == 'Centos':
if jdk_version == '8':
public.ExecShell('yum remove java-1.8.0-openjdk java-1.8.0-openjdk-devel -y >>%s' % tmp_file)
elif jdk_version == '11':
public.ExecShell('yum remove java-11-openjdk java-11-openjdk-devel -y >>%s' % tmp_file)
else:
return public.returnMsg(False, 'JDK version can only be 8 or 11!')
# public.WriteFile(tmp_file,'Successify','a+')
return public.returnMsg(True, 'Uninstallation successful')
elif os_version == 'Ubuntu':
if jdk_version == '8':
public.ExecShell('apt-get remove -y openjdk-8-jre openjdk-8-jdk >>%s' % tmp_file)
elif jdk_version == '11':
public.ExecShell('apt-get remove -y openjdk-11-jre openjdk-11-jdk>>%s' % tmp_file)
else:
return public.returnMsg(False, 'JDK version can only be 8 or 11!')
# public.WriteFile(tmp_file,'Successify','a+')
return public.returnMsg(True, 'Uninstallation successful')
def check_jdk(self, jdk_path=None):
'''
@name Check if JDK version is available
@author lkq<2021-08-25>
@param get<dict_obj>
@return string
'''
java_path = jdk_path + '/jre/bin/java'
java_path2 = jdk_path + '/bin/java'
if os.path.exists(java_path):
ret = public.ExecShell(java_path + ' -version')
if ret[0].find('Error occurred') != -1:
return False
return java_path
elif os.path.exists(java_path2):
ret = public.ExecShell(java_path2 + ' -version')
if ret[0].find('Error occurred') != -1:
return False
return java_path2
else:
return False
def replace_jdk_version(self, get):
'''
@name Modify JDK version
@author lkq<2021-08-27>
@param get.tomcat_start tomcat startup script path
@param get.jdk_path JDK path
@return string
'''
jdk_path = get.jdk_path.strip()
jdk_path2 = jdk_path.split('/')
if jdk_path2[-1] == 'java':
if jdk_path2[-3] == 'jre':
jdk_path2 = '/'.join(jdk_path2[:-3])
if jdk_path2[-2] == 'bin':
jdk_path2 = '/'.join(jdk_path2[:-2])
else:
jdk_path2 = '/'.join(jdk_path2[:-1])
# Check if JDK is available
jdk_path = jdk_path2
jdk_data = self.check_jdk(jdk_path)
if not jdk_data: return public.returnMsg(False, 'Please enter the correct JDK path, for example: /www/server/jdk1.8/bin/java')
if jdk_data:
if not os.path.exists(jdk_data): return public.returnMsg(False, 'JDK directory does not exist!')
if not jdk_data: return public.returnMsg(False, 'The entered JDK is not available!')
tomcat_start = get.tomcat_start.strip()
if not os.path.exists(tomcat_start): return public.returnMsg(False, 'Tomcat startup script does not exist!')
tomcat_start_file = public.ReadFile(tomcat_start)
if isinstance(tomcat_start_file, str):
# 正则匹配到jdk_path
jdk_path_re = re.findall('^JAVA_HOME=(.*)$', tomcat_start_file, re.M)
if jdk_path_re:
tomcat_start_file = tomcat_start_file.replace(jdk_path_re[0], jdk_path)
public.WriteFile(tomcat_start, tomcat_start_file)
# 重启服务
public.ExecShell('bash %s stop' % (tomcat_start))
public.ExecShell('bash %s start' % (tomcat_start))
return public.returnMsg(True, 'Modification successful!')
return public.returnMsg(False, 'Modification failed!')
def get_tomcat_version(self, get):
'''
@name Get Tomcat version information
@author lkq<2021-08-27>
@param get<dict_obj>
@return string
'''
ret = ["7", "8", "9", "10"]
default_path = "/usr/local/btjdk/jdk8/bin/java"
ret2 = {
'tomcat7': {'status': False, "jdk_path": default_path},
'tomcat8': {'status': False, "jdk_path": default_path},
'tomcat9': {'status': False, "jdk_path": default_path},
'tomcat10': {'status': False, "jdk_path": default_path},
}
rep_deemon_sh = re.compile(r"^JAVA_HOME=(?P<path>.*)\n", re.M)
for i in ret:
tmp_path = self.__bttomcat_path + '/tomcat' + i + "/bin/daemon.sh"
if os.path.exists(tmp_path):
tmp_data = public.readFile(tmp_path)
if isinstance(tmp_data, str):
re_res_jdk_path = rep_deemon_sh.search(tmp_data)
if re_res_jdk_path:
ret2["tomcat" + i]["jdk_path"] = re_res_jdk_path.group("path").strip()
ret2["tomcat" + i]["status"] = True
ret2["tomcat" + i]["path"] = self.__bttomcat_path + '/tomcat' + i
ret2["tomcat" + i]["start_path"] = "/etc/init.d/bttomcat" + i
ret2["tomcat" + i]["info"] = self.get_tomcat_info(version = i)
if i == '7':
ret2["tomcat" + i]["tomcat_server"] = self.__tomcat7_server
ret2["tomcat" + i]["tomcat_start"] = self.__tomcat7_path + '/bin/daemon.sh'
elif i == '8':
ret2["tomcat" + i]["tomcat_server"] = self.__tomcat8_server
ret2["tomcat" + i]["tomcat_start"] = self.__tomcat8_path + '/bin/daemon.sh'
elif i == '9':
ret2["tomcat" + i]["tomcat_server"] = self.__tomcat9_server
ret2["tomcat" + i]["tomcat_start"] = self.__tomcat9_path + '/bin/daemon.sh'
elif i == '10':
ret2["tomcat" + i]["tomcat_server"] = '/usr/local/bttomcat/tomcat10/conf/server.xml'
ret2["tomcat" + i]["tomcat_start"] = "/usr/local/bttomcat/tomcat10/bin/daemon.sh"
return ret2
def get_tomcat_info(self, version):
'''
@name Get Tomcat version information
@author lkq<2021-08-27>
@param version Tomcat version 7 8 9
@return string
'''
tmp = {}
tmp_path = '/usr/local/bttomcat/tomcat%s/conf/server.xml' % version
if os.path.exists(tmp_path):
if not self.Initialization(version):
tmp["port"] = False
else:
tmp["port"] = self.get_port()
tmp['status'] = self.get_server(version)
tmp['conf'] = public.readFile(tmp_path)
tmp['jdk_path'] = self.get_jdk_path(version)
# tmp['log'] = public.GetNumLines('/usr/local/bttomcat/tomcat%s/logs/catalina-daemon.out'%version, 3000)
tmp['stype'] = 'built'
else:
tmp['status'] = False
tmp["port"] = False
tmp['conf'] = False
tmp['jdk'] = False
tmp['log'] = False
tmp['stype'] = 'uninstall'
return tmp
def install_tomcat(self, get):
'''
@name Install Tomcat version
@author lkq<2021-08-27>
@param get<dict_obj>
@param get.version Version to install|uninstall
@param get.type install == Install uninstall == Uninstall
@return string
'''
tmp_file = '/tmp/panelShell2.pl'
if not os.path.exists(tmp_file):
public.ExecShell("touch /tmp/panelShell2.pl")
else:
public.ExecShell("echo ""> /tmp/panelShell2.pl")
version = str(get.version)
os_ver = self.get_os_version(None)
if 'type' not in get:
return public.returnMsg(False, 'Parameter error!')
type_list = ['install', 'uninstall']
if not get.type in type_list:
return public.returnMsg(False, 'Installation and uninstallation can only be install or uninstall!')
if version == "7":
if os_ver == 'Ubuntu':
return public.returnMsg(False, 'Operating system not supported!')
download_url = self.test_download_url()
if get.type != 'install' and os.path.exists("/tmp/1.sh"):
public.ExecShell("bash /tmp/1.sh %s %s >>%s" % (get.type, version, tmp_file))
else:
if download_url is None:
error = '<br>Error: Unable to connect to the Baota official website. Please follow the steps below to resolve the issue and try again:<br>Solution: <a target="_blank" class="btlink" href="https://www.bt.cn/bbs/thread-87257-1-1.html">https://www.bt.cn/bbs/thread-87257-1-1.html</a><br>'
raise public.PanelError(error)
# return public.returnMsg(False, 'Network connection error<br>Please check the network configuration or change the node')
public.ExecShell(
"rm -rf /tmp/1.sh && /usr/local/curl/bin/curl -o /tmp/1.sh %s/install/src/webserver/shell/new_jdk.sh && bash /tmp/1.sh %s %s >>%s" % (
download_url, get.type, version, tmp_file)
)
# self.collect_msg("tomcat-{}".format(version), log_path=tmp_file)
tomcat_status = self.get_tomcat_version(None)
if get.type == 'install':
if tomcat_status['tomcat' + version]['status']:
return public.returnMsg(True, 'Installation successful!')
else:
return public.returnMsg(False, 'Installation failed!')
else:
if not tomcat_status['tomcat' + version]['status']:
return public.returnMsg(True, 'Uninstallation successful!')
else:
return public.returnMsg(False, 'Uninstallation failed!')
@staticmethod
def test_download_url():
_sh = """
. /www/server/panel/install/public.sh
curl -s -o /dev/null "${NODE_URL}"
if [ $? -ne 0 ]; then
echo "Network connection error"
exit
fi
echo "${NODE_URL}"
"""
res: str = public.ExecShell(_sh)[0]
if res.find("Network connection error") != -1:
return None
else:
return res.split("\n")[-2].strip()
@staticmethod
def _get_jdk_version_by_jdk_path(jdk_path):
pass
def install_tomcat_new(self, get):
'''
@name Install Tomcat version
@author lkq<2021-08-27>
@param get<dict_obj>
@param get.version Version to install|uninstall
@param get.type install == Install uninstall == Uninstall
@param get.jdk_path Use a different JDK version
@return string
'''
try:
jdk_path = ""
version = str(int(get.version))
action = get.type.strip()
if "jdk_path" in get:
jdk_path = get.jdk_path.strip()
except (AttributeError, TypeError, ValueError):
return public.returnMsg(False, "Parameter error")
if action not in ('install', 'uninstall'):
return public.returnMsg(False, 'Installation and uninstallation can only be install or uninstall!')
os_ver = self.get_os_version(None)
if version == "7":
if os_ver == 'Ubuntu':
return public.returnMsg(False, 'Operating system not supported!')
if jdk_path:
if jdk_path.endswith("/bin/java"):
jdk_path = jdk_path[:-9]
_, error = public.ExecShell("{}/bin/java -version".format(jdk_path)) # Information in standard error
# public.print_log(_)
# public.print_log(error)
if not (error.find("version") != -1 and error.find("Runtime") != -1):
return public.returnMsg(False, "The specified JDK is not available")
tmp_file = '/tmp/panelShell2.pl'
public.writeFile(tmp_file, "")
download_url = self.test_download_url()
if download_url is None:
error = (
'<br>Error: The connection to the Baota official website is abnormal. Please follow the following steps to troubleshoot the problem and try again:<br>Solution:'
'<a target="_blank" class="btlink" href="https://www.bt.cn/bbs/thread-87257-1-1.html">'
'https://www.bt.cn/bbs/thread-87257-1-1.html</a><br>'
)
raise public.PanelError(error)
shell_str = (
'rm -rf /tmp/1.sh && '
'wget -O /tmp/1.sh %s/install/src/webserver/shell/new_jdk.sh && '
'bash /tmp/1.sh %s %s %s >>%s'
) % (download_url, action, version, jdk_path, tmp_file)
# shell_str = (
# 'bash /tmp/1.sh %s %s %s >>%s'
# ) % (action, version, jdk_path, tmp_file)
# public.print_log(shell_str)
_, _ = public.ExecShell(shell_str)
# self.collect_msg("tomcat-{}".format(version), log_path=tmp_file)
tomcat_status = self.get_tomcat_version(None)
if action == 'install':
if tomcat_status['tomcat' + version]['status']:
return public.returnMsg(True, 'Installation successful!')
else:
return public.returnMsg(False, 'Installation failed!')
else:
if not tomcat_status['tomcat' + version]['status']:
return public.returnMsg(True, 'Uninstallation successful!')
else:
return public.returnMsg(False, 'Uninstallation failed!')
@staticmethod
def change_tomcat_jdk(get):
try:
version_str = get.version
if version_str.startswith("tomcat") or version_str.startswith("Tomcat"):
version_str = version_str.replace("tomcat", "").replace("Tomcat", "")
version = str(int(version_str))
jdk_path: str = get.jdk_path.strip()
except (AttributeError, TypeError, ValueError):
return public.returnMsg(False, "Parameter error")
if not os.path.exists(jdk_path):
return public.returnMsg(False, "The specified JDK path does not exist")
if jdk_path.endswith("/bin/java"):
jdk_path = jdk_path[:-9]
_, error = public.ExecShell("{}/bin/java -version".format(jdk_path)) # Information in standard error
if not (error.find("version") != -1 and error.find("Runtime") != -1):
return public.returnMsg(False, "The specified JDK is not available")
tomcat_path = "/usr/local/bttomcat/tomcat{}".format(version)
if not os.path.isdir(tomcat_path):
return public.returnMsg(False, 'Tomcat{} is not installed!'.format(version))
deemon_sh_path = "{}/bin/daemon.sh".format(tomcat_path)
if not os.path.isfile(deemon_sh_path):
return public.returnMsg(False, 'Tomcat{} startup file is missing!'.format(version))
deemon_sh_data = public.readFile(deemon_sh_path)
if not isinstance(deemon_sh_data, str):
return public.returnMsg(False, 'Failed to read Tomcat{} startup file!'.format(version))
# deemon_sh
rep_deemon_sh = re.compile(r"^JAVA_HOME=(?P<path>.*)\n", re.M)
re_res_deemon_sh = rep_deemon_sh.search(deemon_sh_data)
if not re_res_deemon_sh:
return public.returnMsg(False, 'Failed to parse Tomcat{} startup file!'.format(version))
jsvc_make_path = None
for i in os.listdir(tomcat_path + "/bin"):
tmp_dir = "{}/bin/{}".format(tomcat_path, i)
if i.startswith("commons-daemon") and os.path.isdir(tmp_dir):
make_path = tmp_dir + "/unix"
if os.path.isdir(make_path):
jsvc_make_path = make_path
break
if jsvc_make_path is None:
return public.returnMsg(False, 'Jsvc{} file is missing!'.format(version))
# Reinstall jsvc
if os.path.isfile(tomcat_path + "/bin/jsvc"):
os.remove(tomcat_path + "/bin/jsvc")
if os.path.isfile(jsvc_make_path + "/jsvc"):
os.remove(jsvc_make_path + "/jsvc")
shell_str = r'''
cd {}
make clean
./configure --with-java={}
make
\cp jsvc {}
'''.format(jsvc_make_path, jdk_path, tomcat_path + "/bin/jsvc")
public.ExecShell(shell_str)
new_deemon_sh_data = deemon_sh_data[:re_res_deemon_sh.start()] + (
'JAVA_HOME={}\n'.format(jdk_path)
) + deemon_sh_data[re_res_deemon_sh.end():]
public.writeFile(deemon_sh_path, new_deemon_sh_data)
return public.returnMsg(True, 'Modification successful')
def change_duli_tomcat_jdk(self, project_name, jdk_path):
project_info = self.get_project_find(project_name)
if not project_info:
return public.returnMsg(False, "Project does not exist")
project_conf = project_info['project_config']
if project_conf["java_type"] != "duli":
return public.returnMsg(False, "Project type error")
if not os.path.exists(jdk_path):
return public.returnMsg(False, "The specified JDK path does not exist")
if jdk_path.endswith("/bin/java"):
jdk_path = jdk_path[:-9]
_, error = public.ExecShell("{}/bin/java -version".format(jdk_path)) # Information in standard error
if not (error.find("version") != -1 and error.find("Runtime") != -1):
return public.returnMsg(False, "The specified JDK is not available")
tomcat_path = "/www/server/bt_tomcat_web/{}".format(project_name)
if not os.path.isdir(tomcat_path):
return public.returnMsg(False, 'Tomcat is not installed!')
deemon_sh_path = "{}/bin/daemon.sh".format(tomcat_path)
if not os.path.isfile(deemon_sh_path):
return public.returnMsg(False, 'Tomcat startup file is missing!')
deemon_sh_data = public.readFile(deemon_sh_path)
if not isinstance(deemon_sh_data, str):
return public.returnMsg(False, 'Failed to read Tomcat startup file!')
# deemon_sh
rep_deemon_sh = re.compile(r"^JAVA_HOME=(?P<path>.*)\n", re.M)
re_res_deemon_sh = rep_deemon_sh.search(deemon_sh_data)
if not re_res_deemon_sh:
return public.returnMsg(False, 'Failed to parse Tomcat startup file!')
jsvc_make_path = None
for i in os.listdir(tomcat_path + "/bin"):
tmp_dir = "{}/bin/{}".format(tomcat_path, i)
if i.startswith("commons-daemon") and os.path.isdir(tmp_dir):
make_path = tmp_dir + "/unix"
if os.path.isdir(make_path):
jsvc_make_path = make_path
break
if jsvc_make_path is None:
return public.returnMsg(False, 'Jsvc file is missing!')
# Reinstall jsvc
if os.path.isfile(tomcat_path + "/bin/jsvc"):
os.remove(tomcat_path + "/bin/jsvc")
if os.path.isfile(jsvc_make_path + "/jsvc"):
os.remove(jsvc_make_path + "/jsvc")
shell_str = r'''
cd {}
make clean
./configure --with-java={}
make
\cp jsvc {}
'''.format(jsvc_make_path, jdk_path, tomcat_path + "/bin/jsvc")
public.ExecShell(shell_str)
new_deemon_sh_data = deemon_sh_data[:re_res_deemon_sh.start()] + (
'JAVA_HOME={}\n'.format(jdk_path)
) + deemon_sh_data[re_res_deemon_sh.end():]
public.writeFile(deemon_sh_path, new_deemon_sh_data)
project_conf["jdk_path"] = jdk_path
public.M('sites').where("name=?", (project_name,)).update({"project_config": json.dumps(project_conf)})
return public.returnMsg(True, 'Modification successful')
def xml_init(self, path):
'''
@name Initialize XML file
@author lkq<2021-08-27>
@param path<string>
@return string
'''
try:
self.__CONF_FILE = str(path)
self.__TREE = ElementTree()
self.__TREE.parse(self.__CONF_FILE)
self.__ROOT = self.__TREE.getroot()
self.__ENGINE = self.__TREE.findall('Service/Engine')[0]
self.__CONNECTROR = self.__TREE.findall('Service/Connector')
return True
except Exception as e:
return False
def Initialization(self, version):
'''
@name Initialize XML file
@author lkq<2021-08-27>
@param version<string>
@return string
'''
if version == '7' or version == 'tomcat7' or version == 7:
if self.xml_init(self.__tomcat7_server):
return True
else:
return False
elif version == '8' or version == 'tomcat8' or version == 8:
if self.xml_init(self.__tomcat8_server):
return True
else:
return False
elif version == '9' or version == 'tomcat9' or version == 9:
if self.xml_init(self.__tomcat9_server):
return True
else:
return False
elif version == '10' or version == 'tomcat10' or version == 10:
if self.xml_init('/usr/local/bttomcat/tomcat10/conf/server.xml'):
return True
else:
return False
else:
return False
def get_server(self, version, domain=None):
'''
@name Retrieve service status
@author lkq<2021-08-27>
@param version<string>
@return string
'''
if domain:
pid_path = self.__site_path + '/' + domain + '/logs/catalina-daemon.pid'
else:
pid_path = self.__bttomcat_path + '/tomcat%s/logs/catalina-daemon.pid' % version
if os.path.exists(pid_path):
reuslt = public.ReadFile(pid_path)
if isinstance(reuslt, str):
if not reuslt.strip(): return False
pid = int(reuslt.split()[0].strip())
else:
return False
try:
ret = psutil.Process(pid)
return True
except:
return False
else:
return False
def get_port(self):
'''
@name Retrieve port number
@author lkq<2021-08-27>
@param version<string>
@return string
'''
for i in self.__CONNECTROR:
if 'protocol' in i.attrib and 'port' in i.attrib:
if i.attrib['protocol'] == 'HTTP/1.1':
return int(i.attrib['port'])
else:
return int(8080)
def set_tomcat_duli_path(self, get, get_project_find=''):
'''
@name Change independent project path
@author lkq<2021-09-17>
@param get.project_path<int>
@param get.project_name Project name
'''
project_name = get.project_name.strip()
project_info = get_project_find
if not project_info: return public.returnMsg(False, 'Failed to change project path!')
if project_info['project_config']['java_type'] == 'duli':
# Independent project
project_path = get.project_path.strip()
if not os.path.exists(project_path): os.makedirs(project_path)
if not self.Initialization2(version = '7', site = project_name): return public.returnMsg(
False, "Tomcat configuration file error, please check the configuration file"
)
ret = self.Set_Domain_path(project_name, project_path)
if ret:
# Update database
# project_info['path']=project_path
project_info['project_config']['project_cwd'] = project_path
pdata = {
'path': project_path,
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (project_name,)).update(pdata)
return public.returnMsg(True, 'Project path changed successfully!')
else:
return public.returnMsg(False, 'Failed to change project path!')
if project_info['project_config']['java_type'] == 'neizhi':
project_path = get.project_path.strip()
if not os.path.exists(project_path): os.makedirs(project_path)
if not self.Initialization(
version = project_info['project_config']['tomcat_version']
): return public.returnMsg(False, "Tomcat configuration file error, please check the configuration file")
ret = self.Set_Domain_path(project_name, project_path)
if ret:
project_info['project_config']['project_cwd'] = project_path
pdata = {
'path': project_path,
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (project_name,)).update(pdata)
return public.returnMsg(True, 'Project path changed successfully!')
else:
return public.returnMsg(False, 'Failed to change project path!')
def set_tomcat_duli_port(self, get, get_project_find=''):
'''
@name Change independent project port
@author lkq<2021-08-27>
@param get.port<int>
@param get.project_name Project name
'''
project_name = get.project_name.strip()
project_info = get_project_find
if not project_info: return public.returnMsg(False, 'Project does not exist!')
if project_info['project_config']['java_type'] == 'duli':
# Independent project
port = str(get.port)
if self.check_port_is_used(port): return public.returnMsg(False, 'Port is already in use!')
if not self.Initialization2(version = '7', site = project_name): return public.returnMsg(
False, "Configuration file error, please check the configuration file"
)
ret = self.TomcatSetPort(port = port)
if ret:
get.domain = project_name
get.type = 'reload'
self.pendent_tomcat_start(get)
fs = firewalls.firewalls()
get = mobj()
get.port = port
get.ps = 'tomcat external port'
fs.AddAcceptPort(get)
# Change database
project_info['project_config']['port'] = int(port)
pdata = {'project_config': json.dumps(project_info['project_config'])}
public.M('sites').where('name=?', (project_name,)).update(pdata)
# self.set_config(get)
return public.returnMsg(True, 'Change successful!')
else:
return public.returnMsg(False, 'Change failed')
if project_info['project_config']['java_type'] == 'neizhi':
port = str(get.port)
if self.check_port_is_used(port): return public.returnMsg(False, 'Port is already in use!')
if not self.Initialization(
version = project_info['project_config']['tomcat_version']
): return public.returnMsg(False, "Configuration file error, please check the configuration file")
ret = self.TomcatSetPort(port = port)
if ret:
get.version = project_info['project_config']['tomcat_version']
get.type = 'reload'
self.start_tomcat(get)
fs = firewalls.firewalls()
get = mobj()
get.port = port
get.ps = 'tomcat external port'
fs.AddAcceptPort(get)
# Change database
project_info['project_config']['port'] = int(port)
pdata = {'project_config': json.dumps(project_info['project_config'])}
public.M('sites').where('name=?', (project_name,)).update(pdata)
return public.returnMsg(True, 'Change successful!')
else:
return public.returnMsg(False, 'Change failed')
def get_jdk_path(self, version, is_independent=False):
'''
@name Get JDK version path
@author lkq<2021-08-27>
@param version<string>
@param is_independent<bool> Whether it is an independent version
@return string
'''
if is_independent:
path = self.__site_path + '/%s/bin/daemon.sh' % version
else:
path = self.__bttomcat_path + '/tomcat%s/bin/daemon.sh' % version
if os.path.exists(path):
ret = public.ReadFile(path)
if isinstance(ret, str):
rec = "\nJAVA_HOME=.+"
if re.search(rec, ret):
jdk = re.search(rec, ret)
if not jdk: return ''
if jdk:
jdk = jdk.group(0).split('=')[1].strip()
return jdk
else:
return ''
else:
return ''
else:
return ''
def format(self, em, level=0):
'''
@name Format configuration file
@author lkq<2021-08-27>
@param em<string>
@param level<int>
'''
i = "\n" + level * " "
if len(em):
if not em.text or not em.text.strip():
em.text = i + " "
for e in em:
self.format(e, level + 1)
if not e.tail or not e.tail.strip():
e.tail = i
if level and (not em.tail or not em.tail.strip()):
em.tail = i
# 保存配置
def save_tomcat(self):
'''
@name Save Tomcat configuration file
@author lkq<2021-08-27>
'''
self.format(self.__ROOT)
self.__TREE.write(self.__CONF_FILE, 'utf-8')
def get_vhost(self, domain):
'''
@name Retrieve the specified virtual host
@author lkq<2021-08-27>
@param domain<string>
@return string
'''
try:
Hosts = self.__ENGINE.getchildren()
except:
Hosts = list(self.__ENGINE)
for host in Hosts:
if host.tag != 'Host': continue
if host.attrib['name'] == domain:
return host
return None
def add_vhost(self, path, domain):
'''
@name tomcat Fill in virtual host
@author lkq<2021-08-27>
@param path<string>
@param domain<string>
@return bool
'''
if not os.path.exists(path): os.makedirs(path)
if self.get_vhost(domain): return False
attr = {
"autoDeploy": "true", "name": domain, "unpackWARs": "true",
"xmlNamespaceAware": "false", "xmlValidation": "false"
}
Host = Element("Host", attr)
attr = {"docBase": path, "path": "", "reloadable": "true", "crossContext": "true", }
Context = Element("Context", attr)
Host.append(Context)
self.__ENGINE.append(Host)
self.save_tomcat()
return True
# Tomcat service management
def start_tomcat(self, get):
version = str(get.version)
s_type = get.type
if version.startswith('tomcat') or version.startswith('Tomcat'):
version = version.replace('tomcat', '').replace('Tomcat', '')
# Check if the service is running
execStr = '/etc/init.d/bttomcat%s stop && /etc/init.d/bttomcat%s start' % (version, version)
start = '/usr/local/bttomcat/tomcat%s/bin/daemon.sh start' % version
stop = '/usr/local/bttomcat/tomcat%s/bin/daemon.sh stop' % version
if s_type == 'start':
ret = self.get_server(version)
if not ret:
pid_path = '/www/server/%s/logs/catalina-daemon.pid' % version
if os.path.exists(pid_path):
os.remove(pid_path)
public.ExecShell(start)
self.start_by_user("/etc/init.d/bttomcat{}".format(version))
return public.returnMsg(True, 'Start successful')
elif s_type == 'stop':
public.ExecShell(stop)
if self.get_server(version):
public.ExecShell(stop)
self.stop_by_user("/etc/init.d/bttomcat{}".format(version))
return public.returnMsg(True, 'Stop successful')
elif s_type == 'reload' or s_type == 'restart':
# public.ExecShell(execStr)
public.ExecShell(stop)
public.ExecShell(start)
return public.returnMsg(True, 'Reload successful')
else:
return public.returnMsg(False, 'Invalid type')
def pendent_tomcat_start(self, get):
'''
Tomcat Launch for Independent Projects
@author lkq 2021-08-27
@param get.domain Project Domain Name
@param get.type Startup type start stop reload
'''
version = get.domain
s_type = get.type
# Check if the service is running
execStr = '%s/%s/bin/daemon.sh stop && %s/%s/bin/daemon.sh start' % (
self.__site_path, version, self.__site_path, version)
start = '%s/%s/bin/daemon.sh start' % (self.__site_path, version)
stop = '%s/%s/bin/daemon.sh stop' % (self.__site_path, version)
if s_type == 'start':
ret = self.get_server(version, version)
if not ret:
pid_path = '%s/%s/logs/catalina-daemon.pid' % (self.__site_path, version)
if os.path.exists(pid_path):
os.remove(pid_path)
public.ExecShell(start)
self.start_by_user(self.__site_path + "/" + version)
return public.returnMsg(True, 'Startup successful')
elif s_type == 'stop':
public.ExecShell(stop)
if self.get_server(version, version):
public.ExecShell(stop)
self.stop_by_user(self.__site_path + "/" + version)
return public.returnMsg(True, 'Stop successful')
elif s_type == 'reload' or s_type == 'restart':
# public.ExecShell(execStr)
public.ExecShell(stop)
public.ExecShell(start)
return public.returnMsg(True, 'Reload successful')
else:
return public.returnMsg(False, 'Invalid type')
def pendent_tomcat_info(self, get=None, domain=None):
'''
@name Independent project information
@author lkq 2021-08-27
'''
if get: domain = get.domain.strip()
tmp = {}
tmp_path = self.__site_path + '' + domain + '/conf/server.xml'
if os.path.exists(tmp_path):
if not self.Initialization2('7', domain):
tmp["port"] = False
else:
tmp["port"] = self.get_port()
tmp['status'] = self.get_server(domain, domain)
tmp['conf'] = public.readFile(tmp_path)
tmp['jdk_path'] = self.get_jdk_path(domain, True)
# tmp['log'] = public.GetNumLines('%s/%s/logs/catalina-daemon.out'%(self.__site_path,domain), 3000)
tmp["tomcat_server"] = tmp_path
tmp['tomcat_start'] = self.__site_path + '' + domain + '/bin/daemon.sh'
tmp['stype'] = 'built'
else:
tmp['status'] = False
tmp["port"] = False
tmp['conf'] = False
tmp['jdk'] = False
tmp['log'] = False
tmp['jdk_path'] = False
tmp['stype'] = 'uninstall'
return tmp
def exists_nginx_ssl(self, project_name):
'''
@name Determine whether the project is configured with Nginx SSL configuration
@author hwliang<2021-08-09>
@param project_name: string<Project Name>
@return tuple
'''
config_file = "{}/nginx/java_{}.conf".format(public.get_vhost_path(), project_name)
if not os.path.exists(config_file):
return False, False
config_body = public.readFile(config_file)
if not config_body:
return False, False
is_ssl, is_force_ssl = False, False
if config_body.find('ssl_certificate') != -1:
is_ssl = True
if config_body.find('HTTP_TO_HTTPS_START') != -1:
is_force_ssl = True
return is_ssl, is_force_ssl
def set_nginx_config(self, project_find):
'''
@name Set Nginx Configuration
@author hwliang<2021-08-09>
@param project_find: dict<Project Information>
@return bool
'''
project_name = project_find['name']
ports = []
domains = []
for d in project_find['project_config']['domains']:
domain_tmp = d.split(':')
if len(domain_tmp) == 1: domain_tmp.append(80)
if not int(domain_tmp[1]) in ports:
ports.append(int(domain_tmp[1]))
if not domain_tmp[0] in domains:
domains.append(domain_tmp[0])
listen_ipv6 = public.listen_ipv6()
is_ssl, is_force_ssl = self.exists_nginx_ssl(project_name)
listen_ports_list = []
for p in ports:
listen_ports_list.append(" listen {};".format(p))
if listen_ipv6:
listen_ports_list.append(" listen [::]:{};".format(p))
ssl_config = ''
if is_ssl:
http3_header = ""
if self.is_nginx_http3():
http3_header = '''\n add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';'''
http3_header += "\n quic_retry on;\n quic_gso on;"
if self.ng_ssl_early_data_enabled():
http3_header += "\n ssl_early_data on;"
nginx_ver = public.nginx_version()
if nginx_ver:
port_str = ["443"]
if listen_ipv6:
port_str.append("[::]:443")
use_http2_on = False
for p in port_str:
listen_str = " listen {} ssl".format(p)
if nginx_ver < [1, 9, 5]:
listen_str += ";"
elif [1, 9, 5] <= nginx_ver < [1, 25, 1]:
listen_str += " http2;"
else: # >= [1, 25, 1]
listen_str += ";"
use_http2_on = True
listen_ports_list.append(listen_str)
if self.is_nginx_http3():
listen_ports_list.append(" listen {} quic;".format(p))
if use_http2_on:
listen_ports_list.append(" http2 on;")
if self.is_nginx_http3():
listen_ports_list.append(" http3 on;")
else:
listen_ports_list.append(" listen 443 ssl;")
ssl_config = '''ssl_certificate {vhost_path}/cert/{priject_name}/fullchain.pem;
ssl_certificate_key {vhost_path}/cert/{priject_name}/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";{http3_header}
error_page 497 https://$host$request_uri;'''.format(
vhost_path = self._vhost_path, priject_name = project_name,
http3_header = http3_header
)
if is_force_ssl:
ssl_config += '''
#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END'''
config_file = "{}/nginx/java_{}.conf".format(self._vhost_path, project_name)
template_file = "{}/template/nginx/java_http.conf".format(self._vhost_path)
listen_ports = "\n".join(listen_ports_list).strip()
config_body = public.readFile(template_file)
if project_find['project_config']['java_type'] == 'neizhi' or project_find['project_config'][
'java_type'] == 'duli':
host = '{}'.format(project_find['project_config']['project_name'])
else:
host = '$Host'
# api_url='/' if not 'api_url' in project_find['project_config'] else project_find['project_config']['api_url']
# site_path=project_find['path'] if not 'static_path' in project_find['project_config'] else project_find['project_config']['static_path']
# host_url = host if not 'host_url' in project_find['project_config'] else project_find['project_config']['host_url']
if 'host_url' in project_find['project_config']:
if project_find['project_config']['host_url']:
url2 = project_find['project_config']['host_url']
else:
url2 = 'http://127.0.0.1:{}'.format(project_find['project_config']['port'])
else:
url2 = 'http://127.0.0.1:{}'.format(project_find['project_config']['port'])
if project_find["project_config"]["java_type"] == "springboot":
_site_path = project_find["project_config"]["static_path"] if (
"static_path" in project_find["project_config"] and project_find["project_config"][
"static_path"]) else \
project_find["project_config"]["jar_path"]
else:
_site_path = project_find['path']
mut_config = {
"api_url": '/' if not 'api_url' in project_find['project_config'] else project_find['project_config'][
'api_url'],
"site_path": _site_path,
"domains": ' '.join(domains),
"url": url2,
"listen_ports": listen_ports,
"ssl_config": ssl_config,
}
config_body = config_body.format(
api_url = mut_config["api_url"],
site_path = mut_config["site_path"],
domains = ' '.join(domains),
project_name = project_name,
panel_path = self._panel_path,
log_path = public.get_logs_path(),
url = url2,
host = host,
listen_ports = listen_ports,
ssl_config = ssl_config
)
# # Restore old SSL configuration
# ssl_config = self.get_nginx_ssl_config(project_name)
# if ssl_config:
# config_body.replace('#error_page 404/404.html;',ssl_config)
rewrite_file = "{panel_path}/vhost/rewrite/java_{project_name}.conf".format(
panel_path = self._panel_path, project_name = project_name
)
if not os.path.exists(rewrite_file):
public.writeFile(rewrite_file, '# Please fill in the pseudo-static rules or custom NGINX configuration here\n')
if not os.path.exists("/www/server/panel/vhost/nginx/well-known"):
os.makedirs("/www/server/panel/vhost/nginx/well-known", 0o600)
apply_check = "{}/vhost/nginx/well-known/{}.conf".format(self._panel_path, project_name)
from mod.base.web_conf import ng_ext
config_body = ng_ext.set_extension_by_config(project_name, config_body)
if not os.path.exists(apply_check):
public.writeFile(apply_check, '')
if not os.path.exists(config_file):
public.writeFile(config_file, config_body)
else:
if not self._replace_nginx_conf(config_file, mut_config):
public.writeFile(config_file, config_body)
return True
@staticmethod
def _replace_nginx_conf(config_file, mut_config: dict) -> bool:
"""Attempt to replace Nginx configuration"""
data: str = public.readFile(config_file)
tab_spc = " "
rep_list = [
(
r"([ \f\r\t\v]*listen[^;\n]*;\n(\s*http2\s+on\s*;[^\n]*\n)?)+",
mut_config["listen_ports"] + "\n"
),
(
r"[ \f\r\t\v]*root [ \f\r\t\v]*/[^;\n]*;",
" root {};".format(mut_config["site_path"])
),
(
r"[ \f\r\t\v]*server_name [ \f\r\t\v]*[^\n;]*;",
" server_name {};".format(mut_config["domains"])
),
(
r"[ \f\r\t\v]*location [^{\n]* { *\n *proxy_pass[^\n;]*;\n *proxy_set_header *Host",
"{}location {} {{\n{}proxy_pass {};\n{}proxy_set_header Host".format(
tab_spc, mut_config["api_url"], tab_spc * 2, mut_config["url"], tab_spc * 2, )
),
(
"[ \f\r\t\v]*#SSL-START(.*\n){2,15}[ \f\r\t\v]*#SSL-END",
"{}#SSL-START SSL related configuration\n{}#error_page 404/404.html;\n{}{}\n{}#SSL-END".format(
tab_spc, tab_spc, tab_spc, mut_config["ssl_config"], tab_spc
)
)
]
for rep, info in rep_list:
if re.search(rep, data):
data = re.sub(rep, info, data, 1)
else:
return False
public.writeFile(config_file, data)
return True
def exists_apache_ssl(self, project_name):
'''
@name Determine whether the project is configured with Apache SSL configuration
@author hwliang<2021-08-09>
@param project_name: string<Project Name>
@return bool
'''
config_file = "{}/apache/java_{}.conf".format(public.get_vhost_path(), project_name)
if not os.path.exists(config_file):
return False, False
config_body = public.readFile(config_file)
if not config_body:
return False, False
is_ssl, is_force_ssl = False, False
if config_body.find('SSLCertificateFile') != -1:
is_ssl = True
if config_body.find('HTTP_TO_HTTPS_START') != -1:
is_force_ssl = True
return is_ssl, is_force_ssl
def set_apache_config(self, project_find):
'''
@name Set Apache Configuration
@author hwliang<2021-08-09>
@param project_find: dict<Project Information>
@return bool
'''
project_name = project_find['name']
# Process domains and ports
ports = []
domains = []
for d in project_find['project_config']['domains']:
domain_tmp = d.split(':')
if len(domain_tmp) == 1: domain_tmp.append(80)
if not int(domain_tmp[1]) in ports:
ports.append(int(domain_tmp[1]))
if not domain_tmp[0] in domains:
domains.append(domain_tmp[0])
config_file = "{}/apache/java_{}.conf".format(self._vhost_path, project_name)
template_file = "{}/template/apache/java_http.conf".format(self._vhost_path)
config_body = public.readFile(template_file)
apache_config_body = ''
# Check if the old configuration file has SSL configured
is_ssl, is_force_ssl = self.exists_apache_ssl(project_name)
if is_ssl:
if not 443 in ports: ports.append(443)
from panelSite import panelSite
s = panelSite()
if project_find["project_config"]["java_type"] == "springboot":
_site_path = project_find["project_config"]["jar_path"]
else:
_site_path = project_find['path']
# Generate configuration based on the list of ports
for p in ports:
# Generate SSL configuration
ssl_config = ''
if p == 443 and is_ssl:
ssl_key_file = "{vhost_path}/cert/{project_name}/privkey.pem".format(
project_name = project_name, vhost_path = public.get_vhost_path()
)
if not os.path.exists(ssl_key_file): continue # Skip if the certificate file does not exist
ssl_config = '''#SSL
SSLEngine On
SSLCertificateFile {vhost_path}/cert/{project_name}/fullchain.pem
SSLCertificateKeyFile {vhost_path}/cert/{project_name}/privkey.pem
SSLCipherSuite EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5
SSLProtocol All -SSLv2 -SSLv3 -TLSv1
SSLHonorCipherOrder On'''.format(project_name = project_name, vhost_path = public.get_vhost_path())
else:
if is_force_ssl:
ssl_config = '''#HTTP_TO_HTTPS_START
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$
RewriteRule (.*) https://%{SERVER_NAME}$1 [L,R=301]
</IfModule>
#HTTP_TO_HTTPS_END'''
# Generate vhost main body configuration
apache_config_body += config_body.format(
site_path = _site_path,
server_name = '{}.{}'.format(p, project_name),
domains = ' '.join(domains),
log_path = public.get_logs_path(),
server_admin = 'admin@{}'.format(project_name),
url = 'http://127.0.0.1:{}'.format(project_find['project_config']['port']),
port = p,
ssl_config = ssl_config,
project_name = project_name
)
apache_config_body += "\n"
# Add port to the main configuration file
if not p in [80]:
s.apacheAddPort(p)
# Write .htaccess
if project_find["project_config"]["java_type"] == "springboot":
_path = project_find["project_config"]["static_path"] if (
"static_path" in project_find["project_config"] and project_find["project_config"][
"static_path"]) else \
project_find["project_config"]["jar_path"]
rewrite_file = "{}/.htaccess".format(_path)
else:
rewrite_file = "{}/.htaccess".format(project_find['path'])
if not os.path.exists(rewrite_file): public.writeFile(
rewrite_file, '# Please fill in the pseudo-static rules or custom Apache configuration here\n'
)
from mod.base.web_conf import ap_ext
apache_config_body = ap_ext.set_extension_by_config(project_name, apache_config_body)
# Write configuration file
public.writeFile(config_file, apache_config_body)
return True
def get_nginx_ssl_config(self, project_name):
'''
@name Get Nginx SSL configuration for the project
@author hwliang<2021-08-09>
@param project_name: string<Project Name>
@return string
'''
result = ''
config_file = "{}/nginx/java_{}".format(self._vhost_path, project_name)
if not os.path.exists(config_file):
return result
config_body = public.readFile(config_file)
if not config_body:
return result
if config_body.find('ssl_certificate') == -1:
return result
ssl_body = re.search("#SSL-START(.|\n)+#SSL-END", config_body)
if not ssl_body: return result
result = ssl_body.group()
return result
def set_config(self, project_name):
'''
@name Set project configuration
@author hwliang<2021-08-09>
@param project_name: string<Project Name>
@return bool
'''
project_find = self.get_project_find(project_name)
if not project_find: return False
if not project_find['project_config']: return False
if not project_find['project_config']['bind_extranet']: return False
if not project_find['project_config']['domains']: return False
self.set_nginx_config(project_find)
self.set_apache_config(project_find)
public.serviceReload()
return True
def clear_nginx_config(self, project_find):
'''
@name Clear Nginx configuration
@author hwliang<2021-08-09>
@param project_find: dict<Project Information>
@return bool
'''
project_name = project_find['name']
config_file = "{}/nginx/java_{}.conf".format(self._vhost_path, project_name)
if os.path.exists(config_file):
os.remove(config_file)
rewrite_file = "{panel_path}/vhost/rewrite/java_{project_name}.conf".format(
panel_path = self._panel_path, project_name = project_name
)
if os.path.exists(rewrite_file):
os.remove(rewrite_file)
return True
def clear_apache_config(self, project_find):
'''
@name Clear Apache configuration
@author hwliang<2021-08-09>
@param project_find: dict<Project Information>
@return bool
'''
project_name = project_find['name']
config_file = "{}/apache/java_{}.conf".format(self._vhost_path, project_name)
if os.path.exists(config_file):
os.remove(config_file)
return True
def clear_config(self, project_name):
'''
@name Clear project configuration
@author hwliang<2021-08-09>
@param project_name: string<Project Name>
@return bool
'''
project_find = self.get_project_find(project_name)
if not project_find: return False
self.clear_nginx_config(project_find)
self.clear_apache_config(project_find)
public.serviceReload()
return True
def del_vhost(self, domain, context_path: str = ""):
'''
@name Delete virtual host
@author lkq
@param domain: string
@return bool
'''
if domain == 'localhost': return False
host = self.get_vhost(domain)
if not host: return False
target_context, other_context_count = None, 0
for i in host:
if i.tag == "Context":
if i.attrib["path"] == context_path:
target_context = i
else:
other_context_count += 1
if target_context is None and not other_context_count:
return False
if target_context is not None:
host.remove(target_context)
if not other_context_count:
self.__ENGINE.remove(host)
self.save_tomcat()
return True
def tomcat_vhost_delete(self, version, domains, get):
'''
@name Remove the built-in Tomcat virtual host
@author lkq
@param version: string
@param domain: string
@return bool
'''
if not self.Initialization(version): return public.returnMsg(False, "Configuration file error, please check the configuration file")
context_path = get.get("project_name", "")
domain = domains[0].split(":")[0]
if self.del_vhost(domain, context_path):
get.version = version
get.type = 'reload'
self.start_tomcat(get)
return public.returnMsg(True, 'Deletion successful')
return public.returnMsg(False, 'Does not exist')
def set_hosts(self, domain):
'''
@name Set local HOST
'''
pass
ret = public.ReadFile('/etc/hosts')
# if isinstance(ret, str):
# import re
# rec = '%s' % domain
# if not re.search(rec, ret):
# public.ExecShell('echo "127.0.0.1 ' + domain + '" >> /etc/hosts')
@staticmethod
def set_spring_user():
'''
@name Set local HOST
'''
try:
pwd.getpwnam('springboot')
except KeyError:
public.ExecShell('useradd springboot')
def del_hosts(self, domain):
'''
@name Delete local HOST
'''
pass
# ret = public.ReadFile('/etc/hosts')
# if isinstance(ret, str):
# import re
# rec = '127.0.0.1 %s' % domain
# if re.search(rec, ret):
# ret=ret.replace(rec,'')
# public.writeFile('/etc/hosts',ret)
def Initialization2(self, version, site):
'''
@name Initialize independent project
@author lkq 2021-08-28
@param site: string<Project Name>
@param version: string<Version>
'''
# ! The initialization of the project related to Tomcat has been moved to Tomcat version management
if self.xml_init(self.__site_path + site + '/conf/server.xml'):
return True
# if version == '7' or version == 'tomcat7' or version == 7:
# if self.xml_init(self.__site_path + site + '/conf/server.xml'):
# return True
# else:
# return False
# elif version == '8' or version == 'tomcat8' or version == 8:
# if self.xml_init(self.__site_path + site + '/conf/server.xml'):
# return True
# else:
# return False
# elif version == '9' or version == 'tomcat9' or version == 9:
# if self.xml_init(self.__site_path + site + '/conf/server.xml'):
# return True
# else:
# return False
# else:
# return False
def replce_tomcat_port(self, get):
'''
@name Change Tomcat port
@param get.port: int
@param get.version: string
'''
port = str(get.port)
version = str(get.version)
if version.startswith('tomcat') or version.startswith('Tomcat'):
version = version.replace('tomcat', '').replace('Tomcat', '')
if self.IsOpen(port): return public.returnMsg(False, 'The port is already occupied!')
if not self.Initialization(version): return public.returnMsg(False, "Configuration file error, please check the configuration file")
ret = self.TomcatSetPort(port = port)
if ret:
# Reload Tomcat
get.type = 'reload'
self.start_tomcat(get)
return public.returnMsg(True, 'Port change successful')
return public.returnMsg(False, 'Port change failed')
def replace_duli_port(self, get):
'''
@name Change duli port
@param get.port: int
@param get.version: string
@param get.domain string
@return bool
'''
return self.set_site_port(get.port, "", get.domain.strip())
def TomcatSetPort(self, port):
'''
@name Change Tomcat port
@author lkq
@param port: string<Port number>
'''
for i in self.__CONNECTROR:
if 'protocol' in i.attrib and 'port' in i.attrib:
if i.attrib['protocol'] == 'HTTP/1.1':
i.attrib['port'] = port
self.save_tomcat()
if self.get_port() == int(port):
return True
else:
return False
# Retrieve the specified virtual host
def Set_Domain_path(self, domain, docBase):
try:
Hosts = self.__ENGINE.getchildren()
except:
Hosts = list(self.__ENGINE)
flag = False
for host in Hosts:
if host.tag != 'Host': continue
if host.attrib['name'] == domain:
try:
ch = host.getchildren()
except:
ch = list(host)
for i in ch:
print(i.attrib)
if 'docBase' in i.attrib:
i.attrib['docBase'] = docBase
flag = True
if flag:
self.save_tomcat()
return True
return False
def TomcatSetPath(self, port):
'''
@name Change Tomcat project path
@author lkq
@param port: string<Port number>
'''
for i in self.__CONNECTROR:
if 'protocol' in i.attrib and 'port' in i.attrib:
if i.attrib['protocol'] == 'HTTP/1.1':
i.attrib['port'] = port
self.save_tomcat()
if self.get_port() == int(port):
return True
else:
return False
def set_site_port(self, port, version, domain):
'''
@name 更改独立项目端口
@param port: int<端口>
@param version: string<版本>
@param domain: string<域名>
@author lkq 2021-08-28
'''
if self.IsOpen(port): return public.returnMsg(False, 'The port is already occupied!')
if not self.Initialization2(version, domain): return public.returnMsg(False, "Configuration file error, please check the configuration file")
ret = self.TomcatSetPort(port = port)
if ret:
fs = firewalls.firewalls()
get = mobj()
get.port = port
get.ps = 'tomcat external port'
fs.AddAcceptPort(get)
return public.returnMsg(True, 'Change successful!')
else:
return public.returnMsg(False, 'Change failed')
def _get_jdk_status(self):
default_version = {
"x64": [
"jdk1.7.0_80",
"jdk1.8.0_371",
"jdk-9.0.4",
"jdk-10.0.2",
"jdk-11.0.19",
"jdk-12.0.2",
"jdk-13.0.2",
"jdk-14.0.2",
"jdk-15.0.2",
"jdk-16.0.2",
"jdk-17.0.8",
"jdk-18.0.2.1",
"jdk-19.0.2",
"jdk-20.0.2"
],
"arm": [
"jdk1.8.0_371",
"jdk-11.0.19",
"jdk-15.0.2",
"jdk-16.0.2",
"jdk-17.0.8",
"jdk-18.0.2.1",
"jdk-19.0.2",
"jdk-20.0.2"
],
"loongarch64": [
"jdk-8.1.18", "jdk-11.0.22", "jdk-17.0.10", "jdk-21.0.2"
]
}
tmp_file = '/www/server/panel/data/jdk.json'
tmp_pl = '/www/server/panel/data/jdk.json.pl'
download_url = '{}/src/jdk/jdk.json'.format(public.get_url())
setup_path = public.GetConfigValue('setup_path') + '/java'
file_data = public.readFile(tmp_pl)
if not file_data and os.path.exists(tmp_pl):
os.remove(tmp_pl)
if not os.path.exists(setup_path):
public.ExecShell('mkdir -p ' + setup_path)
public.ExecShell('chown 755 ' + setup_path)
if not os.path.exists(tmp_pl) or time.time() - int(file_data) > 3600:
public.run_thread(public.downloadFile, (download_url, tmp_file))
public.writeFile(tmp_pl, str(int(time.time())))
versions = default_version
else:
try:
import json
versions = json.loads(public.readFile(tmp_file))
except:
versions = default_version
# 获取本机系统架构
import platform
arce = platform.machine()
if arce == 'x86_64':
arce = 'x64'
elif arce == 'aarch64' or 'arm' in arce:
arce = 'arm'
try:
versions = versions.get(arce, [])
data = {
"name": "jdk",
"check": "/usr/local/java/VERSION/bin/java",
"msg": "Java is a general-purpose, object-oriented programming language",
"shell": "java.sh",
"task": "1",
"type": "Language Interpreter",
"versions": [
{"status": True if os.path.exists('/www/server/java/' + i) else False, "version": i}
for i in versions]
}
return data
except:
import json
versions_data = public.readFile(tmp_file)
if not versions_data:
versions = default_version
versions = versions.get(arce, [])
else:
versions = json.loads(versions_data).get(arce, [])
data = {
"name": 'jdk',
"check": "/usr/local/java/VERSION/bin/java",
"msg": "Java is a general-purpose, object-oriented programming language",
"shell": "java.sh",
"task": "1",
"type": "Language Interpreter",
"versions": [{'status': False, "name": i} for i in versions]
}
return data
# def get_local_jdk_version(self, get=None):
# '''
# @name 获取本地jdk版本
# @parcm get<>
# @return list
# operation 0 1 2 3 0表示安装 1表示删除 2表示不可操作,3正在安装
# '''
# ret = []
# # 获取本地文件中的JDK版本
# if os.path.exists(self._panel_path + '/data/get_local_jdk.json'):
# ret2 = public.ReadFile(self._panel_path + '/data/get_local_jdk.json')
# if isinstance(ret2, str):
# ret2 = json.loads(ret2)
# for i in range(len(ret2)):
# ret.append({'name': '自定义JDK', 'path': ret2[len(ret)], 'operation': 1})
# jdks = self._get_jdk_status()['versions']
# jdks = sorted(jdks, key=lambda x: x['status'], reverse=True)
# for jdk in jdks:
# if jdk['status']:
# ret.append({'name': jdk['version'], 'path': '/www/server/java/' + jdk['version'] + '/bin/java',
# 'operation': 1})
# else:
# ret.append({'name': jdk['version'], 'path': '', 'operation': 0})
# for i in ret:
# if os.path.exists('/www/server/java/' + i['name'] + '.pl'):
# i['operation'] = 3
# if os.path.exists('/usr/bin/java'):
# ret.append({'name': 'JDK', 'path': '/usr/bin/java', 'operation': 2})
# if os.path.exists('/usr/java/jdk1.8.0_121/bin/java'):
# ret.append({'name': 'jdk8', 'path': '/usr/java/jdk1.8.0_121/bin/java', 'operation': 2})
# if os.path.exists('/usr/local/btjdk/jdk8/bin/java'):
# ret.append({'name': 'openjdk8', 'path': '/usr/local/btjdk/jdk8/bin/java', 'operation': 2})
# if os.path.exists('/usr/java/jdk1.7.0_80/bin/java'):
# ret.append({'name': 'jdk7', 'path': '/usr/java/jdk1.7.0_80/bin/java', 'operation': 2})
# return ret
def get_local_jdk_version(self, get=None):
import os
import json
# 获取本地文件中的JDK版本
ret = []
if os.path.exists(self._panel_path + '/data/get_local_jdk.json'):
ret2 = public.ReadFile(self._panel_path + '/data/get_local_jdk.json')
if isinstance(ret2, str):
ret2 = json.loads(ret2)
for i in range(len(ret2)):
ret.append({'name': 'Custom JDK', 'path': ret2[i], 'operation': 1, 'is_current': False})
# 读取/etc/profile文件来获取当前JAVA_HOME环境变量
bashrc_path = os.path.expanduser('/etc/profile')
current_java_home = ''
# 检查文件是否存在
if os.path.exists(bashrc_path):
profile_data = public.readFile(bashrc_path)
if profile_data:
for line in profile_data.strip("\n"):
if 'export JAVA_HOME=' in line:
current_java_home = line.split('=')[1].strip().replace('"', '').replace("'", "")
# 获取已安装的JDK版本
jdks = self._get_jdk_status()['versions']
jdks = sorted(jdks, key = lambda x: x['status'], reverse = True)
for jdk in jdks:
jdk_path = '/www/server/java/' + jdk['version'] + '/bin/java'
is_current = os.path.dirname(os.path.dirname(jdk_path)) == current_java_home
if jdk['status']:
ret.append({'name': jdk['version'], 'path': jdk_path, 'operation': 1, 'is_current': is_current})
else:
ret.append({'name': jdk['version'], 'path': '', 'operation': 0, 'is_current': False})
# 检查其他JDK路径
jdk_paths = [
('JDK', '/usr/bin/java'),
('jdk8', '/usr/java/jdk1.8.0_121/bin/java'),
('openjdk8', '/usr/local/btjdk/jdk8/bin/java'),
('jdk7', '/usr/java/jdk1.7.0_80/bin/java')
]
for name, path in jdk_paths:
if os.path.exists(path):
is_current = os.path.dirname(os.path.dirname(path)) == current_java_home
ret.append({'name': name, 'path': path, 'operation': 2, 'is_current': is_current})
# 检查是否有正在安装的JDK
for i in ret:
import psutil
try:
if os.path.exists('/www/server/java/' + i['name'] + '.pl'):
pid = int(public.readFile('/www/server/java/' + i['name'] + '.pl'))
psutil.Process(pid)
i['operation'] = 3
except UnicodeEncodeError:
continue
except:
public.ExecShell('rm -rf /www/server/java/' + i['name'] + '.pl')
return ret
def get_system_info(self, get):
'''
@name 获取基础信息
'''
reuslt = {}
reuslt['jdk_info'] = self.get_local_jdk_version(get)
reuslt['tomcat_info'] = self.get_tomcat_version(get)
return public.returnMsg(True, reuslt)
def install_jdk_new(self, get):
try:
if not hasattr(get, 'version'):
return public.returnMsg(False, 'Version number cannot be empty')
if not os.path.exists('/www/server/panel/install/jdk.sh'):
public.ExecShell('wget -O /www/server/panel/install/jdk.sh ' + public.get_url() + '/install/0/jdk.sh')
jdk_version = self.get_local_jdk_version()
jdk_version = [i["name"] for i in jdk_version if i["operation"] == 0]
if os.path.exists('/www/server/java/' + get['version']):
return public.returnMsg(False, 'Version already exists')
if get['version'] not in jdk_version:
return public.returnMsg(False, 'Version number does not exist')
public.writeFile('/www/server/java/{}.pl'.format(get['version']), str(os.getpid()))
res = public.ExecShell('bash /www/server/panel/install/jdk.sh install ' + get['version'])
public.ExecShell('rm -rf /www/server/java/{}.*'.format(get['version']))
# self.collect_msg("jdk-{}".format(get['version']), log=res[1] + res[0])
if res[0].find('Java installation successful') == -1:
return public.returnMsg(False, 'Failed to install Java')
return public.returnMsg(True, 'Java installed successfully')
except:
public.ExecShell('rm -rf /www/server/java/{}.*'.format(get['version']))
return public.returnMsg(False, 'Failed to install Java')
# def collect_msg(self, title, log=None, log_path=None):
# from panel_msg import collect_message
# logs_dir = public.get_panel_path() + "/logs/installed"
# if not os.path.exists(logs_dir):
# os.makedirs(logs_dir, 0o600)
# file_path = logs_dir + "/{}_{}.log".format(title, int(time.time()))
#
# if log:
# public.writeFile(file_path, log)
# elif log_path and os.path.isfile(log_path):
# shutil.copyfile(log_path, file_path)
# else:
# public.writeFile(file_path, "{}安装结束".format(title))
#
# data = {
# "soft_name": title,
# "install_status": "安装" + title + "完成",
# "file_name": file_path,
# "self_type": "soft_install",
# "status": 2,
# "task_id": -1
# }
# title = data["install_status"]
# res = collect_message(title, ["软件安装", "软件安装"], ["Java项目", "JAVA环境管理"], data, 'info')
# if isinstance(res, str):
# public.WriteLog("消息盒子", "安装信息收集失败")
# return None
#
# return res
# 添加本地JDK
def add_local_jdk(self, get):
'''
@name 添加本地JDK
@parcm get.jdk<>
@return list
'''
jdk = get.jdk.strip()
loacl_jdk = self.get_local_jdk_version()
local_jdk = [i['path'] for i in loacl_jdk if i['operation'] in [1, 2]]
if jdk in local_jdk: return public.returnMsg(False, 'JDK path already exists')
jdk_path = jdk.split('/')
if jdk_path[-1] != 'java': return public.returnMsg(False, 'Please provide the complete path, for example: /www/server/jdk1.8/bin/java')
if not os.path.exists(jdk): return public.returnMsg(False, 'JDK path does not exist')
if not os.path.exists(self._panel_path + '/data/get_local_jdk.json'):
# 验证JDK是否可用
# if not self.check_jdk(jdk):return public.returnMsg(False,'JDK不可用')
ret = public.ExecShell(jdk + ' -version')
if ret[0].find('Error occurred') != -1:
return public.returnMsg(False, 'JDK is not available')
public.writeFile(self._panel_path + '/data/get_local_jdk.json', json.dumps([jdk]))
return public.returnMsg(True, 'Saved successfully')
else:
ret = public.ExecShell(jdk + ' -version')
if ret[0].find('Error occurred') != -1:
return public.returnMsg(False, 'JDK is not available')
data = public.readFile(self._panel_path + '/data/get_local_jdk.json')
if isinstance(data, str):
data = json.loads(data)
if jdk in data: return public.returnMsg(False, 'Already exists')
data.append(jdk)
public.writeFile(self._panel_path + '/data/get_local_jdk.json', json.dumps(data))
return public.returnMsg(True, 'Saved successfully')
else:
public.writeFile(self._panel_path + '/data/get_local_jdk.json', json.dumps([jdk]))
return public.returnMsg(True, 'Saved successfully')
# 删除本地JDK
def del_local_jdk(self, get):
jdk = get.jdk.strip()
if '/www/server/java/' in jdk:
jdk_version = jdk.split('/')[-3]
public.ExecShell('rm -rf ' + '/www/server/java/' + jdk_version)
data = public.readFile(self._panel_path + '/data/get_local_jdk.json')
if isinstance(data, str):
data = json.loads(data)
if jdk in data:
data.remove(jdk)
public.writeFile(self._panel_path + '/data/get_local_jdk.json', json.dumps(data))
return public.returnMsg(True, 'Deleted successfully')
if not os.path.exists(self._panel_path + '/data/get_local_jdk.json'):
return public.returnMsg(False, 'Deletion failed')
data = public.readFile(self._panel_path + '/data/get_local_jdk.json')
if isinstance(data, str):
data = json.loads(data)
if jdk in data:
data.remove(jdk)
public.writeFile(self._panel_path + '/data/get_local_jdk.json', json.dumps(data))
return public.returnMsg(True, 'Deleted successfully')
else:
return public.returnMsg(False, 'Deletion failed')
else:
return public.returnMsg(False, 'Deletion failed')
def get_process_cpu_time(self, cpu_times):
cpu_time = 0.00
for s in cpu_times: cpu_time += s
return cpu_time
def get_cpu_precent(self, p):
'''
@name 获取进程cpu使用率
@author hwliang<2021-08-09>
@param p: Process<进程对像>
@return dict
'''
skey = "cpu_pre_{}".format(p.pid)
old_cpu_times = cache.get(skey)
process_cpu_time = self.get_process_cpu_time(p.cpu_times())
if not old_cpu_times:
cache.set(skey, [process_cpu_time, time.time()], 3600)
# time.sleep(0.1)
old_cpu_times = cache.get(skey)
process_cpu_time = self.get_process_cpu_time(p.cpu_times())
old_process_cpu_time = old_cpu_times[0]
old_time = old_cpu_times[1]
new_time = time.time()
cache.set(skey, [process_cpu_time, new_time], 3600)
percent = round(
100.00 * (process_cpu_time - old_process_cpu_time) / (new_time - old_time) / psutil.cpu_count(), 2
)
return percent
def get_project_run_state(self, get=None, project_name=None):
'''
@name 获取项目运行状态
@author hwliang<2021-08-12>
@param get<dict_obj>{
project_name: string<项目名称>
}
@param project_name<string> 项目名称
@return bool
'''
if get: project_name = get.project_name.strip()
project_info = self.get_project_find(project_name)
if not project_info: return False
if not 'project_config' in project_info: return False
if not 'pids' in project_info['project_config']: return self.check_project_run_status_by_ps(project_info)
pid_file = project_info['project_config']['pids']
if not os.path.exists(pid_file): return self.check_project_run_status_by_ps(project_info)
try:
pid = int(public.readFile(pid_file))
except:
return self.check_project_run_status_by_ps(project_info)
pids = self.get_project_pids(pid = pid)
if not pids: return self.check_project_run_status_by_ps(project_info)
return True
@staticmethod
def check_project_run_status_by_ps(project_conf: dict) -> bool:
cmd_str = project_conf["project_config"]['project_cmd']
if not isinstance(cmd_str, str):
return False
cmd_str = re.sub(r' {2,}', ' ', cmd_str) # 将可能存在的多个空格更换为单空格
tmp: str = public.ExecShell('ps aux| grep "%s" |grep -v grep' % cmd_str)[0]
if not tmp.strip():
return False
try:
tmp = re.sub(r' {2,}', ' ', tmp)
pids = [int(i.split(' ')[1]) for i in tmp.split("\n") if bool(i)]
except (IndexError, ValueError, TypeError):
return False
running_pid = []
for pid in pids:
if pid in psutil.pids():
running_pid.append(pid)
if not running_pid:
return False
if len(running_pid) == 1:
public.writeFile(project_conf["project_config"]['pids'], str(running_pid[0]))
return True
for pid in running_pid:
p = psutil.Process(pid)
if p.ppid() not in running_pid:
public.writeFile(project_conf["project_config"]['pids'], str(pid))
return True
return False
def get_duli_run_state(self, get=None, project_name=None, bt_tomcat_web='/www/server/bt_tomcat_web', neizhi=False):
'''
@name 获取项目运行状态
@author hwliang<2021-08-12>
@param get<dict_obj>{
project_name: string<项目名称>
}
@param project_name<string> 项目名称
@return bool
'''
if get: project_name = get.project_name.strip()
if neizhi:
pid_file = "{}/logs/catalina-daemon.pid".format(bt_tomcat_web, project_name)
else:
pid_file = "{}/{}/logs/catalina-daemon.pid".format(bt_tomcat_web, project_name)
if not os.path.exists(pid_file):
return False
try:
pid_data = public.readFile(pid_file)
if isinstance(pid_data, str) and bool(pid_data.strip()):
tmp_pid_data = pid_data.split()
if len(tmp_pid_data) < 1:
return False
pid = int(tmp_pid_data[0])
pids = self.get_project_pids(pid = pid)
if not pids: return False
return True
else:
return False
except:
return False
def format_connections(self, connects):
'''
@name 获取进程网络连接信息
@author hwliang<2021-08-09>
@param connects<pconn>
@return list
'''
result = []
for i in connects:
raddr = i.raddr
if not i.raddr:
raddr = ('', 0)
laddr = i.laddr
if not i.laddr:
laddr = ('', 0)
result.append(
{
"fd": i.fd,
"family": i.family,
"local_addr": laddr[0],
"local_port": laddr[1],
"client_addr": raddr[0],
"client_rport": raddr[1],
"status": i.status
}
)
return result
def get_project_load_info(self, get=None, project_name=None):
'''
@name 获取项目负载信息
@author hwliang<2021-08-12>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
if get: project_name = get.project_name.strip()
load_info = {}
# id_file = "{}/{}.pid".format(self._springboot_pid_path,project_name)
project_info = self.get_project_find(project_name)
if not project_info: return load_info
if not 'project_config' in project_info: return load_info
if not 'pids' in project_info['project_config']: return load_info
pid_file = project_info['project_config']['pids']
if not os.path.exists(pid_file): return load_info
try:
pid = int(public.readFile(pid_file))
except:
return load_info
pids = self.get_project_pids(pid = pid)
if not pids: return load_info
for i in pids:
process_info = self.get_process_info_by_pid(i)
if process_info: load_info[i] = process_info
return load_info
def get_duli_load_info(self, get=None, project_name=None, bt_tomcat_web='/www/server/bt_tomcat_web/', neizhi=False):
'''
@name 获取项目负载信息
@author hwliang<2021-08-12>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
if get: project_name = get.project_name.strip()
load_info = {}
if neizhi:
pid_file = "{}/logs/catalina-daemon.pid".format(bt_tomcat_web, project_name)
else:
pid_file = "{}/{}/logs/catalina-daemon.pid".format(bt_tomcat_web, project_name)
if not os.path.exists(pid_file): return load_info
try:
pid_data = public.readFile(pid_file)
except:
return load_info
if isinstance(pid_data, str):
pid = pid_data.split()[0]
pid = int(pid)
else:
return load_info
pids = self.get_project_pids(pid = pid)
if not pids: return load_info
for i in pids:
process_info = self.get_process_info_by_pid(i)
if process_info: load_info[i] = process_info
return load_info
def get_connects(self, pid):
'''
@name 获取进程连接信息
@author hwliang<2021-08-09>
@param pid<int>
@return dict
'''
connects = 0
try:
if pid == 1: return connects
tp = '/proc/' + str(pid) + '/fd/'
if not os.path.exists(tp): return connects
for d in os.listdir(tp):
fname = tp + d
if os.path.islink(fname):
l = os.readlink(fname)
if l.find('socket:') != -1: connects += 1
except:
pass
return connects
def object_to_dict(self, obj):
'''
@name 将对象转换为字典
@author hwliang<2021-08-09>
@param obj<object>
@return dict
'''
result = {}
for name in dir(obj):
value = getattr(obj, name)
if not name.startswith('__') and not callable(value) and not name.startswith('_'): result[name] = value
return result
def list_to_dict(self, data):
'''
@name 将列表转换为字典
@author hwliang<2021-08-09>
@param data<list>
@return dict
'''
result = []
for s in data:
result.append(self.object_to_dict(s))
return result
def get_process_info_by_pid(self, pid):
'''
@name 获取进程信息
@author hwliang<2021-08-12>
@param pid: int<进程id>
@return dict
'''
process_info = {}
try:
if not os.path.exists('/proc/{}'.format(pid)): return process_info
p = psutil.Process(pid)
# status_ps = {'sleeping': '睡眠', 'running': '活动'}
with p.oneshot():
p_mem = p.memory_full_info()
if p_mem.uss + p_mem.rss + p_mem.pss + p_mem.data == 0: return process_info
p_state = p.status()
# if p_state in status_ps: p_state = status_ps[p_state]
# process_info['exe'] = p.exe()
process_info['name'] = p.name()
process_info['pid'] = pid
process_info['ppid'] = p.ppid()
process_info['create_time'] = int(p.create_time())
process_info['status'] = p_state
process_info['user'] = p.username()
process_info['memory_used'] = p_mem.uss
process_info['cpu_percent'] = self.get_cpu_precent(p)
try:
process_info['io_write_bytes'], process_info['io_read_bytes'] = p.io_counters()
except:
process_info['io_write_bytes'], process_info['io_read_bytes'] = 0, 0
process_info['connections'] = self.format_connections(p.connections())
process_info['connects'] = self.get_connects(pid)
process_info['open_files'] = self.list_to_dict(p.open_files())
process_info['threads'] = p.num_threads()
process_info['exe'] = ' '.join(p.cmdline())
return process_info
except:
return process_info
def get_io_speed(self, p):
'''
@name 获取磁盘IO速度
@author hwliang<2021-08-12>
@param p: Process<进程对像>
@return list
'''
skey = "io_speed_{}".format(p.pid)
old_pio = cache.get(skey)
if not hasattr(p, 'io_counters'): return 0, 0
pio = p.io_counters()
if not old_pio:
cache.set(skey, [pio, time.time()], 3600)
# time.sleep(0.1)
old_pio = cache.get(skey)
pio = p.io_counters()
old_write_bytes = old_pio[0].write_bytes
old_read_bytes = old_pio[0].read_bytes
old_time = old_pio[1]
new_time = time.time()
write_bytes = pio.write_bytes
read_bytes = pio.read_bytes
cache.set(skey, [pio, new_time], 3600)
write_speed = int((write_bytes - old_write_bytes) / (new_time - old_time))
read_speed = int((read_bytes - old_read_bytes) / (new_time - old_time))
return write_speed, read_speed
def get_project_find(self, project_name):
'''
@name 获取指定项目配置
@author hwliang<2021-08-09>
@param project_name<string> 项目名称
@return dict
'''
project_info = public.M('sites').where('project_type=? AND name=?', ('Java', project_name)).find()
if isinstance(project_info, str):
raise public.PanelError('Database query error:' + project_info)
if not project_info: return False
project_info['project_config'] = json.loads(project_info['project_config'])
return project_info
def project_remove_domain(self, get):
'''
@name 为指定项目删除域名
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
domain: string<域名>
}
@return dict
'''
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The specified project does not exist')
last_domain = get.domain
domain_arr = get.domain.split(':')
if len(domain_arr) == 1:
domain_arr.append(80)
if domain_arr[0] == get.project_name: return public.returnMsg(False, 'Cannot delete the current project domain')
project_id = public.M('sites').where('name=?', (get.project_name,)).getField('id')
if len(public.M('domain').where('pid=?', (project_find['id'],)).select()) == 1:
return public.returnMsg(False, 'The project requires at least one domain name')
domain_id = public.M('domain').where('name=? AND pid=?', (domain_arr[0], project_id)).getField('id')
if not domain_id:
return public.returnMsg(False, 'The specified domain does not exist')
public.M('domain').where('id=?', (domain_id,)).delete()
if get.domain in project_find['project_config']['domains']:
project_find['project_config']['domains'].remove(get.domain)
if get.domain + ":80" in project_find['project_config']['domains']:
project_find['project_config']['domains'].remove(get.domain + ":80")
public.M('sites').where('id=?', (project_id,)).save(
'project_config', json.dumps(project_find['project_config'])
)
public.WriteLog(self._log_name, 'Deleted domain {} from project: {}'.format(get.domain, get.project_name))
self.set_config(get.project_name)
self.del_hosts(domain_arr[0])
return public.returnMsg(True, 'Domain deleted successfully')
def project_get_domain(self, get):
'''
@name 获取指定项目的域名列表
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
project_id = public.M('sites').where('name=?', (get.project_name,)).getField('id')
if not project_id:
return public.return_data(False, 'Site query failed')
domains = public.M('domain').where('pid=?', (project_id,)).order('id desc').select()
# project_find = self.get_project_find(get.project_name)
# if not project_find:
# return public.return_data(False, '站点查询失败')
# if len(domains) != len(project_find['project_config']['domains']):
# public.M('domain').where('pid=?', (project_id,)).delete()
# if not project_find: return []
# for d in project_find['project_config']['domains']:
# domain = {}
# arr = d.split(':')
# if len(arr) < 2: arr.append(80)
# domain['name'] = arr[0]
# domain['port'] = int(arr[1])
# domain['pid'] = project_id
# domain['addtime'] = public.getDate()
# public.M('domain').insert(domain)
# if project_find['project_config']['domains']:
# domains = public.M('domain').where('pid=?', (project_id,)).select()
return domains
def project_add_domain(self, get):
'''
@name 为指定项目添加域名
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
domains: list<域名列表>
}
@return dict
'''
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The specified project does not exist')
project_id = project_find['id']
domains = get.domains
flag = False
res_domains = []
for domain in domains:
domain = domain.strip()
if not domain: continue
domain_arr = domain.split(':')
domain_arr[0] = self.check_domain(domain_arr[0])
if domain_arr[0] is False:
res_domains.append({"name": domain, "status": False, "msg": 'Invalid domain format'})
continue
if len(domain_arr) == 1:
domain_arr.append("")
if domain_arr[1] == "":
domain_arr[1] = 80
domain += ':80'
try:
if not (0 < int(domain_arr[1]) < 65535):
res_domains.append({"name": domain, "status": False, "msg": 'Invalid domain format'})
continue
except ValueError:
res_domains.append({"name": domain, "status": False, "msg": 'Invalid domain format'})
continue
if not public.M('domain').where('name=?', (domain_arr[0],)).count():
public.M('domain').add(
'name,pid,port,addtime', (domain_arr[0], project_id, domain_arr[1], public.getDate())
)
if not domain in project_find['project_config']['domains']:
project_find['project_config']['domains'].append(domain)
public.WriteLog(self._log_name, 'Successfully added domain {} to project {}'.format(domain, get.project_name))
res_domains.append({"name": domain_arr[0], "status": True, "msg": 'Successfully added'})
flag = True
else:
public.WriteLog(self._log_name, 'Error adding domain, domain {} already exists'.format(domain))
res_domains.append(
{"name": domain_arr[0], "status": False, "msg": 'Error adding, domain {} already exists'.format(domain)}
)
if flag:
public.M('sites').where('id=?', (project_id,)).save(
'project_config', json.dumps(project_find['project_config'])
)
self.set_config(get.project_name)
return self._ckeck_add_domain(get.project_name, res_domains)
def get_other_pids(self, pid):
'''
@name 获取其他进程pid列表
@author hwliang<2021-08-10>
@param pid: string<项目pid>
@return list
'''
plugin_name = None
for pid_name in os.listdir(self._springboot_pid_path):
pid_file = '{}/{}'.format(self._springboot_pid_path, pid_name)
try:
s_pid = int(public.readFile(pid_file))
except:
continue
if pid == s_pid:
plugin_name = pid_name[:-4]
break
project_find = self.get_project_find(plugin_name)
if not project_find: return []
if not self._pids: self._pids = psutil.pids()
all_pids = []
for i in self._pids:
try:
p = psutil.Process(i)
if p.cwd() == project_find['project_config']['jar_path'] and p.username() == \
project_find['project_config']['run_user']:
if p.name() in ['java', 'jsvc', 'jsvc.exec']:
all_pids.append(i)
except:
continue
return all_pids
def get_project_pids(self, get=None, pid=None):
'''
@name 获取项目进程pid列表
@author hwliang<2021-08-10>
@param pid: string<项目pid>
@return list
'''
if get: pid = int(get.pid)
if not self._pids: self._pids = psutil.pids()
project_pids = []
if pid not in self._pids: return []
for i in self._pids:
try:
p = psutil.Process(i)
if p.status() == "zombie":
continue
if p.ppid() == pid:
if i in project_pids:
continue
project_pids.append(i)
except:
continue
other_pids = []
for i in project_pids:
other_pids += self.get_project_pids(pid = i)
if os.path.exists('/proc/{}'.format(pid)):
project_pids.append(pid)
all_pids = list(set(project_pids + other_pids))
# if not all_pids:
# all_pids = self.get_other_pids(pid)
return sorted(all_pids)
def stop_project(self, get):
'''
@name 停止项目
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
project_info = self.get_project_find(get.project_name.strip())
if not project_info: return public.returnMsg(False, 'The specified project does not exist')
project_find = self.get_project_find(get.project_name)
if project_find['edate'] != "0000-00-00" and project_find['edate'] < datetime.datetime.today().strftime("%Y-%m-%d"):
return public.return_error('The current project has expired, please reset the project expiration date')
if project_info['project_config']['java_type'] == 'springboot':
# pid_file = "{}/{}.pid".format(self._springboot_pid_path,get.project_name)
pid_file = project_info['project_config']['pids']
if not os.path.exists(pid_file): return public.returnMsg(False, 'The project is not running')
try:
pid = int(public.readFile(pid_file))
except:
return public.returnMsg(False, 'The project is not running')
pids = self.get_project_pids(pid = pid)
if not pids: return public.returnMsg(False, 'The project is not running')
self.kill_pids(pids = pids)
if os.path.exists(pid_file): os.remove(pid_file)
self.stop_by_user(project_info["id"])
return public.returnMsg(True, 'Stopped successfully')
if project_info['project_config']['java_type'] == 'duli':
get.domain = project_info['name']
get.type = 'stop'
return self.pendent_tomcat_start(get)
if project_info['project_config']['java_type'] == 'neizhi':
get.version = project_info['project_config']['tomcat_version']
get.type = 'stop'
return self.start_tomcat(get)
def restart_project(self, get):
'''
@name 重启项目
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
project_find = self.get_project_find(get.project_name)
if project_find['edate'] != "0000-00-00" and project_find['edate'] < datetime.datetime.today().strftime("%Y-%m-%d"):
return public.return_error('The current project has expired, please reset the project expiration date')
res = self.stop_project(get)
if not res['status']: return res
res = self.start_project(get)
if not res['status']: return res
return public.returnMsg(True, 'Restarted successfully')
def start_project(self, get):
'''
@name 启动项目
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
project_find = self.get_project_find(get.project_name)
if not project_find: return public.returnMsg(False, 'The specified project does not exist')
project_find = self.get_project_find(get.project_name)
if project_find['edate'] != "0000-00-00" and project_find['edate'] < datetime.datetime.today().strftime("%Y-%m-%d"):
return public.return_error('The current project has expired, please reset the project expiration date')
self._update_project(get.project_name, project_find)
if project_find['project_config']['java_type'] == 'duli':
get.domain = project_find['name']
get.type = 'start'
return self.pendent_tomcat_start(get)
if project_find['project_config']['java_type'] == 'neizhi':
get.version = project_find['project_config']['tomcat_version']
get.type = 'start'
return self.start_tomcat(get)
if project_find['project_config']['java_type'] == 'springboot':
project_cmd = project_find["project_config"]['project_cmd']
# 前置准备
log_file = project_find["project_config"]['logs']
pid_file = project_find["project_config"]['pids']
nohup_log = ' &>> {log_file}'.format(log_file = log_file)
if not int(project_find["project_config"].get('nohup_log', 1)):
nohup_log = ''
if 'jar_path' in project_find['project_config']:
jar_path = project_find['project_config']['jar_path']
else:
jar_path = '{}'.format(self._springboot)
# 启动脚本
start_cmd = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
cd {jar_path}
nohup {project_cmd}{nohup_log} &
echo $! > {pid_file}
'''.format(
jar_path = jar_path,
project_cmd = project_cmd,
pid_file = pid_file,
log_file = log_file,
nohup_log = nohup_log
)
script_file = project_find["project_config"]['scripts']
# 写入启动脚本
public.writeFile(script_file, start_cmd)
if os.path.exists(pid_file): os.remove(pid_file)
public.ExecShell("chmod -R 777 /var/tmp/springboot/")
# public.ExecShell("chown -R {}:{} {}".format(project_find['project_config']['run_user'],project_find['project_config']['run_user'],self._springboot))
public.set_mode(script_file, 755)
public.ExecShell(
"chown {}:{} {}".format(
project_find['project_config']['run_user'], project_find['project_config']['run_user'],
project_find['path']
)
)
if not os.path.exists(log_file): public.ExecShell("touch {}".format(log_file))
public.ExecShell(
"chown {}:{} {}".format(
project_find['project_config']['run_user'], project_find['project_config']['run_user'], log_file
)
)
self._pass_dir_for_user(os.path.dirname(log_file), project_find['project_config']['run_user'])
# 判断是否在/www/ /www/wwwroot
# 执行脚本文件
p = public.ExecShell(
"bash {}".format(script_file), user = project_find['project_config']['run_user'],
env = os.environ.copy()
)
time.sleep(1)
if not os.path.exists(pid_file):
return public.returnMsg(False, 'Failed to start, please try switching the startup user')
# 获取PID
try:
pid = int(public.readFile(pid_file))
except:
return public.returnMsg(True, 'Failed to start')
time.sleep(0.4)
pids = self.get_project_pids(pid = pid)
# if not pids:
# if os.path.exists(pid_file): os.remove(pid_file)
# return public.returnMsg(False,'启动失败<br>{}'.format(public.GetNumLines(log_file,20)))
self.start_by_user(project_find["id"])
return public.returnMsg(True, 'Started successfully')
def return_jdkcmd(self, get):
'''
@name 修改JDK 返回所需命令
@param jdK_path
@param cmd
@return string cmd
'''
jdK_path = get.jdK_path.strip()
cmd = get.cmd.strip()
if not os.path.exists(jdK_path): return public.returnMsg(False, 'JDK path does not exist')
cmd2 = cmd.split()
if 'debug' in get:
debug = 1
else:
debug = 0
return_cmd = []
for i in cmd2:
if '/java' in i:
return_cmd.append(jdK_path)
elif '-agentlib:' in i and debug:
continue
else:
return_cmd.append(i)
return public.returnMsg(True, ' '.join(return_cmd))
def send_cmd(self, get):
port = get.port if 'port' in get else self.generate_random_port()
if not hasattr(get, 'project_jdk'):
return public.returnMsg(False, 'Missing parameter! project_jdk')
project_jdk = get.project_jdk
if not os.path.exists(project_jdk): return public.returnMsg(False, 'Project JDK does not exist')
project_jar = get.project_jar.strip()
if not os.path.exists(project_jar): return public.returnMsg(False, 'Project jar does not exist')
jmx_cmd = ""
if hasattr(get, 'jmx_status'):
if get.jmx_status:
jmx_port = self.generate_random_port()
jmx_cmd = "-Dcom.sun.management.jmxremote.port={} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=127.0.0.1".format(
jmx_port
)
if 'debug' in get:
debug_port = self.generate_random_port()
return public.returnMsg(
True,
'{} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address={} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
project_jdk, debug_port, jmx_cmd, project_jar, port
)
)
lib_path_cmd = ""
if hasattr(get, 'lib_path') and get.lib_path:
lib_path_cmd = "-Dloader.path={}".format(get.lib_path)
return public.returnMsg(
True, '{} {} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
project_jdk, lib_path_cmd, jmx_cmd, project_jar,
port
)
)
def return_cmd(self, get):
'''
@name 获取启动的命令
@author lkq<2021-08-27>
@param project_jar 项目jar路径
@param port 项目端口号
@param project_jdk 项目JDK
'''
if 'project_cmd' not in get or not get.project_cmd.strip():
return self.send_cmd(get)
else:
if not get.project_cmd:
return self.send_cmd(get)
# 修改port
project_find = self.get_project_find(get.project_name)
if not project_find:
return self.send_cmd(get)
project_cmd = get.project_cmd.strip()
cmd_type = int(get.type)
jmx_cmd = ""
if hasattr(get, 'jmx_status'):
project_find['project_config']['jmx_status'] = get.jmx_status
if get.jmx_status:
jmx_port = self.generate_random_port()
jmx_cmd = "-Dcom.sun.management.jmxremote.port={} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=127.0.0.1".format(
jmx_port
)
jmx_url = "service:jmx:rmi:///jndi/rmi://127.0.0.1:{}/jmxrmi".format(jmx_port)
project_find['project_config']['jmx_status'] = get.jmx_status
project_find['project_config']['jmx_info'] = {
"jmx_url": jmx_url,
"username": "",
"password": "",
}
if cmd_type == 1:
old_port = str(project_find['project_config']['port']).strip()
if old_port:
project_cmd = project_find['project_config']['project_cmd'].replace(old_port, str(get.port))
else:
res = self.send_cmd(get)
if not res["status"]:
return res
else:
project_cmd = res["msg"]
project_find['project_config']['project_cmd'] = project_cmd
project_find['project_config']['port'] = get.port
project_find['project_config']['project_jdk'] = get.project_jdk.strip()
pdata = {
'name': get.project_name.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
return public.returnMsg(True, project_cmd)
if cmd_type == 2:
if 'project_jdk' in project_find['project_config']:
project_cmd = project_find['project_config']['project_cmd'].replace(
str(project_find['project_config']['project_jdk']), str(get.project_jdk.strip())
)
project_cmd = project_cmd.replace(str(project_find['project_config']['port']), str(get.port))
else:
project_cmd = '{} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
get.project_jdk.strip(), jmx_cmd, get.project_jar.strip(), get.port
)
project_find['project_config']['project_cmd'] = project_cmd
project_find['project_config']['port'] = get.port
project_find['project_config']['project_jdk'] = get.project_jdk.strip()
pdata = {
'name': get.project_name.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
return public.returnMsg(True, project_cmd)
if cmd_type == 3:
if 'debug' in get and get.debug in (True, 1, "1", "true"):
if get.debug:
debug_port = self.generate_random_port()
cmd = '{} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address={} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
get.project_jdk, debug_port, jmx_cmd,
project_find['project_config'][
'project_jar'],
project_find['project_config']['port']
)
project_find['project_config']['project_cmd'] = cmd
project_find['project_config']['port'] = get.port
project_find['project_config']['project_jdk'] = get.project_jdk.strip()
pdata = {
'name': get.project_name.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
return public.returnMsg(True, cmd)
cmd = '{} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
get.project_jdk, jmx_cmd, project_find['project_config']['project_jar'],
project_find['project_config']['port']
)
project_find['project_config']['project_cmd'] = cmd
project_find['project_config']['port'] = get.port
project_find['project_config']['project_jdk'] = get.project_jdk.strip()
pdata = {
'name': get.project_name.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
return public.returnMsg(True, cmd)
if cmd_type == 4: # jmx
cmd = '{} {} -jar -Xmx1024M -Xms256M {} --server.port={}'.format(
get.project_jdk, jmx_cmd, project_find['project_config']['project_jar'],
project_find['project_config']['port']
)
project_find['project_config']['project_cmd'] = cmd
project_find['project_config']['port'] = get.port
project_find['project_config']['project_jdk'] = get.project_jdk.strip()
pdata = {
'name': get.project_name.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
return public.returnMsg(True, cmd)
def unbind_extranet(self, get):
'''
@name 解绑外网
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
project_name = get.project_name.strip()
self.clear_config(project_name)
public.serviceReload()
project_find = self.get_project_find(project_name)
project_find['project_config']['bind_extranet'] = 0
public.M('sites').where("id=?", (project_find['id'],)).setField(
'project_config',
json.dumps(project_find['project_config'])
)
public.WriteLog(self._log_name, 'Java project {}, external network mapping closed'.format(project_name))
return public.returnMsg(True, 'External network mapping closed successfully')
def bind_extranet(self, get):
'''
@name 绑定外网
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
res_msg = self._check_webserver()
if res_msg:
return public.returnMsg(False, res_msg)
if not public.is_apache_nginx(): return public.returnMsg(False, 'Please install Apache or Nginx first!')
project_name = get.project_name.strip()
project_find = self.get_project_find(project_name)
if not project_find: return public.returnMsg(False, 'The specified project does not exist')
if not project_find['project_config']['domains']: return public.returnMsg(
False, 'Please add at least one domain in the 【Domain Management】 option'
)
project_find['project_config']['bind_extranet'] = 1
public.M('sites').where("id=?", (project_find['id'],)).setField(
'project_config', json.dumps(project_find['project_config'])
)
self.set_config(project_name)
public.WriteLog(self._log_name, 'Java project {}, external network mapping enabled'.format(project_name))
return public.returnMsg(True, 'External network mapping enabled successfully')
def create_project(self, get):
'''
@name 创建项目
@author lkq<2021-08-27>
@param project_type 项目类型 1 内置 2 独立 3 Spring_boot 项目
@return string
'''
try:
project_type = int(get.project_type)
except:
return public.returnMsg(False, 'Project type parameter error')
if project_type == 1:
# 检查Nginx/Apache 配置文件是否OK
isError = public.checkWebConfig()
if isError != True:
return public.returnMsg(
False, 'WEB server configuration file error ERROR:<br><font style="color:red;">' + isError.replace(
"\n", '<br>'
) + '</font>'
)
return self.create_internal_project(get)
elif project_type == 2:
# 检查Nginx/Apache 配置文件是否OK
isError = public.checkWebConfig()
if isError != True:
return public.returnMsg(
False, 'WEB server configuration file error ERROR:<br><font style="color:red;">' + isError.replace(
"\n", '<br>'
) + '</font>'
)
return self.create_independent_project(get)
elif project_type == 3:
return self.create_spring_boot_project(get)
def create_internal_project(self, get):
'''
@name 创建内置项目
@author lkq<2021-08-27>
@param domain 域名
@param tomcat_version tomcat版本 7 8 9
@param project_path 项目路径
@param project_ps 项目描述
@param bind_extranet 绑定外网 默认不需要传递
@return string
'''
if not public.is_apache_nginx(): return public.returnMsg(False, 'Apache or Nginx is not installed')
if not 'domain' in get: return public.returnMsg(False, 'Please specify a domain!')
if not 'tomcat_version' in get: return public.returnMsg(False, 'Please specify a Tomcat version!')
if not 'project_path' in get: return public.returnMsg(False, 'Please specify a project path!')
if not 'project_name' in get:
get.project_name = get.domain
else:
get.project_name = get.domain
if not 'bind_extranet' in get:
get.bind_extranet = 1
else:
get.bind_extranet = 1
domain = get.domain.strip()
# 判断域名是合法性
if not self.is_domain(domain): return public.returnMsg(False, "Please enter the correct domain name")
# 兼容PHP 判断域名是否存在
if public.M('domain').where('name=?', domain).count():
return public.returnMsg(False, 'The specified domain already exists: {}'.format(domain))
tomcat_version = str(get.tomcat_version)
project_path = get.project_path.strip()
if not os.path.exists(project_path):
os.makedirs(project_path)
public.set_own(project_path, 'www')
# project_name = get.project_name.strip()
tomcat_list = ["7", "8", "9"]
if not tomcat_version in tomcat_list: return public.returnMsg(False, 'Please specify the Tomcat version!')
# 判断tomcat是否存在
tomcat_info = self.get_tomcat_info(tomcat_version)
if tomcat_info['stype'] == 'uninstall': return public.returnMsg(False, 'The specified Tomcat does not exist!')
# 如果为就旧版本启动文件更改启动文件
res = public.ExecShell('sed -n "142p" /usr/local/bttomcat/tomcat{}/bin/daemon.sh'.format(tomcat_version))[0]
_path = '/www/wwwlogs/java/neizhi{}'.format(tomcat_version)
if not os.path.exists(_path):
os.makedirs(_path)
if not res.startswith('test ".$CATALINA_OUT" = . && CATALINA_OUT="$CATALINA_BASE/logs/catalina-daemon.out"'):
self._change_daemom_sh("/usr/local/bttomcat/tomcat%s/bin/daemon.sh" % tomcat_version, _path)
# 初始化tomcat配置文件
if not self.Initialization(tomcat_version): return public.returnMsg(
False, "Tomcat%s configuration file error or service not installed" % tomcat_version
)
# 获取当前tomcat 的port
tomcat_port = tomcat_info['port']
# 判断域名是否在tomcat中
if self.add_vhost(path = project_path, domain = domain):
# 添加成功
# 添加数据库信息
pdata = {
'name': domain,
'path': project_path,
'ps': get.project_ps,
'status': 1,
'type_id': 0,
'project_type': 'Java',
'project_config': json.dumps(
{
'ssl_path': '/www/wwwroot/java_node_ssl',
'project_name': domain,
'project_cwd': project_path,
'bind_extranet': 1,
'domains': [],
'tomcat_version': tomcat_version,
'java_type': 'neizhi',
'server_xml': '/usr/local/bttomcat/tomcat%s/conf/server.xml' % tomcat_version,
'port': int(tomcat_port),
'auth': '1', ##默认开机自动启动
'nohup_log': get.nohup_log if hasattr(get, 'nohup_log') else 1
}
),
'addtime': public.getDate()
}
domains = []
if get.bind_extranet == 1:
domains.append(domain)
project_id = public.M('sites').insert(pdata)
self.set_hosts(domain)
# 建立反代项目
if get.bind_extranet == 1:
format_domains = []
for domain in domains:
if domain.find(':') == -1: domain += ':80'
format_domains.append(domain)
get.domains = format_domains
self.project_add_domain(get)
self.set_config(domain)
public.WriteLog(self._log_name, 'Add Java project{}'.format(domain))
# 重载服务
# 检查配置文件是否OK 如果存在问题则回退配置文件
get.version = tomcat_version
get.type = 'reload'
self.start_tomcat(get)
return public.returnMsg(True, "Add Java project successfully")
else:
return public.returnMsg(False, "Add Java project failed")
def create_independent_project(self, get):
'''
@name 创建独立项目
@author lkq<2021-08-27>
@param domain 域名
@param project_path 项目路径
@param port 端口号
@param tomcat_version 项目tomcat版本 7 8 9
#param project_ps 项目描述
@param auth 开机自动启动
'''
# 检查是否安装Apache或者Nginx
if not public.is_apache_nginx(): return public.returnMsg(False, 'Apache or Nginx is not installed')
if 'auto' not in get: get.auto = '0'
port = get.port
project_path = get.project_path.strip()
# project_name=get.project_name.strip()
if not hasattr(get, "tomcat_version"):
return public.returnMsg(False, 'Tomcat version not specified')
tomcat_version = str(get.tomcat_version)
domain = get.domain.strip()
if not 'project_name' in get:
get.project_name = get.domain
else:
get.project_name = get.domain
if hasattr(get, 'jdk_path'):
jdk_path = get.jdk_path.strip()
else:
jdk_path = "/usr/local/btjdk/jdk8"
# 判断域名是合法性
if not self.is_domain(domain): return public.returnMsg(False, "Please enter the correct domain name")
# 兼容PHP 判断域名是否存在
if public.M('domain').where('name=?', domain).count():
return public.returnMsg(False, 'The specified domain already exists: {}'.format(domain))
if 'bind_extranet' in get:
get.bind_extranet = 1
else:
get.bind_extranet = 1
tomcat_list = ["7", "8", "9"]
if not tomcat_version in tomcat_list: return public.returnMsg(False, 'Please specify the Tomcat version!')
if int(port) < 1 or int(port) > 65535: return public.returnMsg(False, 'Invalid port range')
if self.check_port(port): return public.returnMsg(False, "Port is occupied, please use another port")
# 判断是否存在
if os.path.exists(self.__site_path + domain): return public.returnMsg(
False, "The specified site already exists. To create a new one, please delete %s" % self.__site_path + domain
)
if not os.path.exists(project_path):
os.makedirs(project_path)
public.set_own(project_path, 'www')
# 首先需要先复制好文件过去
if not os.path.exists(self.__site_path + domain):
public.ExecShell('mkdir -p %s' % self.__site_path + domain)
if tomcat_version == 'tomcat7' or tomcat_version == '7':
if not os.path.exists(self.__tomcat7_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat7 configuration file does not exist, please reinstall Tomcat7"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat7_path_bak, self.__site_path + domain, self.__site_path + domain)
)
if tomcat_version == 'tomcat8' or tomcat_version == '8':
if not os.path.exists(self.__tomcat8_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat8 configuration file does not exist, please reinstall Tomcat8"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat8_path_bak, self.__site_path + domain, self.__site_path + domain)
)
if tomcat_version == 'tomcat9' or tomcat_version == '9':
if not os.path.exists(self.__tomcat9_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat9 configuration file does not exist, please reinstall Tomcat9"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat9_path_bak, self.__site_path + domain, self.__site_path + domain)
)
# server.xml
if os.path.exists(self.__site_path + domain + '/conf/server.xml'):
ret = '''<Server port="{}" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector connectionTimeout="20000" port="8083" protocol="HTTP/1.1" redirectPort="8490" />
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" />
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt" />
</Host>
</Engine>
</Service>
</Server>'''.format(self.generate_random_port())
log_path = "/www/wwwlogs/java/{}".format(get.project_name)
if not os.path.exists(log_path) or os.path.isfile(log_path):
os.makedirs(log_path, mode = 0o777)
if not self._change_daemom_sh(
self.__site_path + domain + '/bin/daemon.sh', log_path, domain.replace(".", '_')
):
os.system('rm -rf %s' % self.__site_path + domain)
return public.returnMsg(False, "Configuration file does not exist, please reinstall Tomcat and try creating the site again")
public.WriteFile(self.__site_path + domain + '/conf/server.xml', ret)
else:
os.system('rm -rf %s' % self.__site_path + domain)
return public.returnMsg(False, "Configuration file does not exist, please reinstall Tomcat and try creating the site again")
if not self.Initialization2(tomcat_version, domain): return public.returnMsg(
False, "Configuration file error or service not installed"
)
# 先改他的端口
ret = self.set_site_port(port, tomcat_version, domain)
if not ret['status']: return ret
ret = self.add_vhost(path = project_path, domain = domain)
if ret:
self.set_hosts(domain)
# 启动实例
pid_path = '/www/server/web_site/%s/logs/catalina-daemon.pid' % domain
if os.path.exists(pid_path):
os.remove(pid_path)
public.ExecShell('sh %s' % self.__site_path + domain + '/bin/daemon.sh start')
# 启动成功后建立反代项目
pdata = {
'name': domain,
'path': project_path,
'ps': get.project_ps,
'status': 1,
'type_id': 0,
'project_type': 'Java',
'project_config': json.dumps(
{
'ssl_path': '/www/wwwroot/java_node_ssl',
'project_name': domain,
'project_cwd': project_path,
'bind_extranet': 1,
'domains': [],
'java_type': 'duli',
'tomcat_version': tomcat_version,
'server_xml': self.__site_path + domain + '/conf/server.xml',
'jdk_path': jdk_path,
'port': int(port),
'auth': get.auth,
'logs': "/www/wwwlogs/java/{}/".format(domain),
'nohup_log': get.nohup_log if hasattr(get, 'nohup_log') else 1
}
),
'addtime': public.getDate()
}
domains = []
if get.bind_extranet == 1:
domains.append(domain)
project_id = public.M('sites').insert(pdata)
self.set_hosts(domain)
# 建立反代项目
if get.bind_extranet == 1:
format_domains = []
for domain in domains:
if domain.find(':') == -1: domain += ':80'
format_domains.append(domain)
get.domains = format_domains
self.project_add_domain(get)
self.set_config(domain)
if jdk_path != "/usr/local/btjdk/jdk8":
self.change_duli_tomcat_jdk(domain, jdk_path)
public.WriteLog(self._log_name, 'Added Java project {}'.format(domain))
return public.returnMsg(True, "Added successfully")
else:
return public.returnMsg(False, "Domain already exists")
def check_port_is_used(self, port, sock=False):
'''
@name 检查端口是否被占用
@author hwliang<2021-08-09>
@param port: int<端口>
@return bool
'''
if not isinstance(port, int): port = int(port)
if port == 0: return False
project_list = public.M('sites').where('status=? AND project_type=?', (1, 'Java')).field(
'name,path,project_config'
).select()
for project_find in project_list:
project_config = json.loads(project_find['project_config'])
if not 'port' in project_config: continue
try:
if int(project_config['port']) == port:
return True
except:
continue
if sock: return False
return public.check_tcp('127.0.0.1', port)
def get_host_url(self, get):
if 'port' in get:
port = get['port']
return 'http://127.0.0.1:'.format(port)
else:
return 'http://127.0.0.1:6611'
def create_spring_boot_project(self, get):
'''
@name 创建Spring_boot项目
@author lkq<2021-08-27>
@param domains 域名 可选
@param project_jar 项目jar路径
@param project_name 项目名称
@param port 项目端口号
@param project_jdk 项目JDK
@param project_cmd 最终执行的命令
@parcm run_user 项目用户
@parcm bind_extranet 是否绑定外网
@param auth 开启自启动
@parcm project_ps 描述
'''
self.set_spring_user()
if get.run_user != 'root':
ret = public.ReadFile('/etc/passwd')
if isinstance(ret, str):
rec = 'springboot'
if not re.search(rec, ret):
return public.returnMsg(
False, 'Springboot user establishment failed, suspected to be intercepted by security software. Manually establish user operations as follows: useradd -s /sbin/nologin springboot'
)
else:
return public.returnMsg(
False, 'Springboot user establishment failed, suspected to be intercepted by security software. Manually establish user operations as follows: useradd -s /sbin/nologin springboot'
)
if not 'project_jdk' in get: return public.returnMsg(False, "Please enter your JDK path")
if not 'project_jar' in get: return public.returnMsg(False, "Please enter your jar path")
if not 'project_name' in get and get.project_name.strip(): return public.returnMsg(False, "Please enter your project name")
if not 'port' in get: return public.returnMsg(False, "Please enter your project port")
if not 'run_user' in get: return public.returnMsg(False, "Please enter your project user")
# if not 'auth' in get: return public.returnMsg(False, "请输入是否开机自启动")
if not 'project_cmd' in get: return public.returnMsg(False, "Please enter your project start command")
if not hasattr(get, 'project_ps'): return public.returnMsg(False, "Please enter your project description")
if not 'project_ps' in get: get.project_ps = ''
if not 'is_separation' in get: get.is_separation = 0
get.project_name = get.project_name.strip()
if public.M('sites').where('name=? ', (get.project_name,)).count():
return public.return_error('Specified project name already exists: {}'.format(get.project_name))
project_path = os.path.dirname(get.project_jar)
if not public.check_site_path(project_path):
a, c = public.get_sys_path()
return public.returnMsg(False, 'Please do not place project files in the following critical directories: <br>{}'.format("<br>".join(a + c)))
if get.is_separation:
if public.get_webserver() == 'apache':
return public.returnMsg(False, "Front-end and back-end separation is not supported with Apache")
get.is_separation = 1
##静态资源目录
if get.is_separation and ('static_path' not in get or not get.static_path.strip()):
get.static_path = '/www/wwwroot/' + get.project_name.split('/')[0]
if 'api_url' not in get or not get.api_url.strip():
get.api_url = '/'
elif get.api_url != '/' and get.api_url[-1] == '/':
get.api_url = get.api_url[:-1]
if not hasattr(get, 'auth'):
get.auth = '0'
if get.is_separation:
if 'host_url' not in get or not get.host_url.strip():
return public.returnMsg(False, "Please enter the backend address you need")
else:
if get.host_url[-1] == '/':
get.host_url = get.host_url[:-1]
if 'domains' in get:
domains = get.domains
if len(domains) >= 1:
get.bind_extranet = 1
# Check if Nginx/Apache configuration files are OK
isError = public.checkWebConfig()
if isError != True:
return public.returnMsg(
False, 'WEB server configuration file error ERROR:<br><font style="color:red;">' + isError.replace(
"\n", '<br>'
) + '</font>'
)
else:
get.bind_extranet = 0
else:
get.domains = []
get.bind_extranet = 0
if public.M('sites').where('name=?', (get.project_name,)).count():
return public.returnMsg(False, 'Specified project name already exists: {}'.format(get.project_name))
project_name = get.project_name.strip()
# if not re.match("^\w+$",project_name):
# return public.return_error('项目名称格式不正确,支持字母、数字、下划线,表达式: ^[0-9A-Za-z_]$')
# 端口占用检测
if self.check_port(get.port):
return public.returnMsg(
False, 'The specified port is already occupied by another application. Please modify your project configuration to use a different port: {}'.format(get.port)
)
# 判断JDK路径是否存在
if not os.path.exists(get.project_jdk): return public.returnMsg(False, 'Please enter the correct JDK path')
domains = []
if get.bind_extranet == 1:
domains = get.domains
for domain in domains:
domain_arr = domain.split(':')
if public.M('domain').where('name=?', domain_arr[0]).count():
return public.returnMsg(False, 'Specified domain already exists: {}'.format(domain))
# 获取jar包的路径
project_jar = get.project_jar.strip()
if not os.path.exists(project_jar): return public.returnMsg(False, 'Please enter the correct jar package path')
# 获取jar的根目录
if not get.is_separation:
get.host_url = False
pdata = {
'name': get.project_name,
'path': get.project_jar,
'ps': get.project_ps,
'status': 1,
'type_id': 0,
'project_type': 'Java',
'project_config': json.dumps(
{
'project_jdk': get.project_jdk.strip(),
'ssl_path': '/www/wwwroot/java_node_ssl',
'project_name': get.project_name.strip(),
'project_jar': get.project_jar.strip(),
'bind_extranet': get.bind_extranet,
'domains': [],
'run_user': get.run_user.strip(),
'jmx_status': getattr(get, "jmx_status", False),
'jmx_info': {
"jmx_url": "service:jmx:rmi:///jndi/rmi://127.0.0.1:{}/jmxrmi".format(get.jmx_port) if hasattr(
get, "jmx_port"
) else None,
"username": "",
"password": "",
},
'port': int(get.port),
'auth': get.auth,
'project_cmd': get.project_cmd.strip(),
'java_type': 'springboot',
'jar_path': project_path,
'pids': self._springboot_pid_path + '/' + get.project_name.strip() + '.pid',
'logs': self._springboot_logs_path + '/' + get.project_name.strip() + '.log',
'scripts': self._springboot_run_scripts + '/' + get.project_name.strip() + '.sh',
'is_separation': get.is_separation,
'static_path': getattr(get, "static_path", None),
'api_url': get.api_url,
'host_url': get.host_url,
'nohup_log': get.nohup_log if hasattr(get, 'nohup_log') else 1
}
),
'addtime': public.getDate()
}
project_id = public.M('sites').insert(pdata)
if get.bind_extranet == 1:
format_domains = []
for domain in domains:
if domain.find(':') == -1: domain += ':80'
format_domains.append(domain)
get.domains = format_domains
self.project_add_domain(get)
self.set_config(get.project_name)
# 设置java启动目录为某个用户权限
public.ExecShell("chown {}:{} {}".format(get.run_user.strip(), get.run_user.strip(), project_path))
if get.is_separation:
if not os.path.exists(get.static_path):
public.ExecShell("mkdir -p {}".format(get.static_path))
public.ExecShell("chown {}:{} {}".format(get.run_user.strip(), get.run_user.strip(), get.static_path))
else:
public.ExecShell(
"chown -R {}:{} {}".format(get.run_user.strip(), get.run_user.strip(), get.static_path)
)
public.WriteLog(self._log_name, 'Added Java Springboot project {}'.format(get.project_name))
self.start_project(get)
# 将所有的监听端口找出来,用于放行
load_info = self.get_project_load_info(project_name = get.project_name)
if load_info:
listen = []
for pid in load_info.keys():
if 'connections' not in load_info[pid]:
continue
for conn in load_info[pid]['connections']:
if not conn['status'] == 'LISTEN':
continue
if not conn['local_port'] in listen:
listen.append(str(conn['local_port']))
if listen:
get.port = ",".join(listen)
flag, tip = self._release_firewall(get)
msg = 'Project added successfully ' + ("" if flag else "<br>" + tip)
if "use_project_watch" in get and get.use_project_watch in ("1", "true", "yes", 1):
add_project_watch(
p_name = get.project_name.strip(),
p_type = "java",
site_id = project_id,
watch_path = get.project_jar.strip()
)
return public.returnMsg(True, msg, project_id)
def kill_pids(self, get=None, pids=None):
'''
@name 结束进程列表
@author hwliang<2021-08-10>
@param pids: string<进程pid列表>
@return dict
'''
if get: pids = get.pids
if not pids: return public.returnMsg(True, 'No process')
pids = sorted(pids, reverse = True)
for i in pids:
try:
p = psutil.Process(i)
p.terminate()
except:
pass
return public.returnMsg(True, 'All processes have ended')
def get_project_list2(self, get):
'''
@name 取项目列表
@author lkq<2021-08-27>
@param domain 域名
@return string
'''
if not 'p' in get: get.p = 1
if not 'limit' in get: get.limit = 12
if not 'callback' in get: get.callback = ''
if not 'order' in get: get.order = 'id desc'
if 'search' in get:
get.project_name = get.search.strip()
search = "%{}%".format(get.project_name)
count = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?)', ('Java', search, search)
).count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?)', ('Java', search, search)
).limit(data['shift'] + ',' + data['row']).order(get.order).select()
else:
count = public.M('sites').where('project_type=?', 'Java').count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where('project_type=?', 'Java').limit(
data['shift'] + ',' + data['row']
).order(get.order).select()
for i in range(len(data['data'])):
project_config = json.loads(data['data'][i]['project_config'])
# 如果内置项目被删除 则直接删除当前项目
if project_config['java_type'] == 'neizhi' or project_config['java_type'] == 'duli':
if not os.path.exists(project_config['server_xml']):
# 删除项目
data['data'][i]['is_file_ok'] = False
else:
data['data'][i]['is_file_ok'] = True
# get.project_name = data['data'][i]['name']
# self.remove_project(get)
# 独立项目如果目录被删除
for i in range(len(data['data'])):
data['data'][i] = self.get_project_stat(data['data'][i])
return data
def get_tomcat_domain(self, get):
verison = str(get.version).strip()
version_list = ["7", "8", "9"]
if verison not in version_list: return public.returnMsg(False, 'Please select a version')
data = public.M('sites').where('project_type=?', ('Java')).select()
ret = []
for i in data:
project_config = json.loads(i['project_config'])
if project_config['java_type'] == 'neizhi':
if project_config["tomcat_version"] == verison:
ret.append(i['name'])
return ret
def get_project_list(self, get):
'''
@name 取项目列表
@author lkq<2021-08-27>
@param domain 域名
@return string
'''
if not 'p' in get: get.p = 1
if not 'limit' in get: get.limit = 20
if not 'callback' in get: get.callback = ''
if not 'order' in get: get.order = 'id desc'
type_id = None
if "type_id" in get:
try:
type_id = int(get.type_id)
except:
type_id = None
if 'search' in get:
get.project_name = get.search.strip()
search = "%{}%".format(get.project_name)
if type_id is None:
count = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?)',
('Java', search, search)
).count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?)',
('Java', search, search)
).limit(
data['shift'] + ',' + data['row']
).order(get.order).select()
else:
count = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?) AND type_id = ?',
('Java', search, search, type_id)
).count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where(
'project_type=? AND (name LIKE ? OR ps LIKE ?) AND type_id = ?',
('Java', search, search, type_id)
).limit(
data['shift'] + ',' + data['row']
).order(get.order).select()
else:
if type_id is None:
count = public.M('sites').where('project_type=?', 'Java').count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where('project_type=?', 'Java').limit(
data['shift'] + ',' + data['row']
).order(get.order).select()
else:
count = public.M('sites').where('project_type=? AND type_id = ?', ('Java', type_id)).count()
data = public.get_page(count, int(get.p), int(get.limit), get.callback)
data['data'] = public.M('sites').where('project_type=? AND type_id = ?', ('Java', type_id)).limit(
data['shift'] + ',' + data['row']
).order(get.order).select()
if isinstance(data["data"], str) and data["data"].startswith("error"):
raise public.PanelError("Database query error" + data["data"])
# 处理内置项目和独立项目是否被删除
for i in range(len(data['data'])):
project_config = json.loads(data['data'][i]['project_config'])
# 如果内置项目被删除 则直接删除当前项目
if project_config['java_type'] == 'neizhi':
if not os.path.exists(project_config['server_xml']):
# 删除项目
data['data'][i]['is_file_ok'] = False
else:
# 判断这个域名是否存在于配置文件中
if not self.Initialization(project_config['tomcat_version']): data['data'][i]['is_file_ok'] = False
if self.get_vhost(data['data'][i]['name']):
data['data'][i]['is_file_ok'] = True
else:
data['data'][i]['is_file_ok'] = False
if project_config['java_type'] == 'duli':
if not os.path.exists(project_config['server_xml']):
data['data'][i]['is_file_ok'] = False
else:
if not self.Initialization2(version = '7', site = data['data'][i]['name']): data['data'][i][
'is_file_ok'] = False
if self.get_vhost(data['data'][i]['name']):
data['data'][i]['is_file_ok'] = True
else:
data['data'][i]['is_file_ok'] = False
for i in range(len(data['data'])):
data['data'][i] = self.get_project_stat(data['data'][i])
project_config = data['data'][i]['project_config']
project_config["use_project_watch"] = use_project_watch(project_config['project_name'])
if 'project_cmd' in project_config:
# 检查project_cmd字段是否包含'-Dloader.path='
if '-Dloader.path=' in project_config['project_cmd']:
# 使用split方法提取出lib路径
lib_path = project_config['project_cmd'].split("-Dloader.path=")[1].split(" ")[0]
# 在返回的项目数据中添加lib_path字段
data['data'][i]['lib_path'] = lib_path
# 返回更新后的data
return data
# 修复独立项目
def fix_project(self, get):
'''
@name 修复项目
@author lkq<2021-08-27>
@param project_name 域名
@return string
'''
if not public.is_apache_nginx(): return public.returnMsg(False, 'Apache or Nginx is not installed')
project_info = self.get_project_find(get.project_name.strip())
if not project_info: return public.returnMsg(False, 'Project does not exist')
project_config = project_info['project_config']
if project_config['java_type'] == 'duli':
if not os.path.exists(
self.__bttomcat_path + "/tomcat_bak{}/conf/server.xml".format(
project_config['tomcat_version']
)
): return public.returnMsg(False, 'Failed to repair, the current Tomcat version is not installed')
tomcat_list = ["7", "8", "9"]
if not project_config['tomcat_version'] in tomcat_list: return public.returnMsg(False, 'Please specify the Tomcat version!')
if self.check_port(str(project_config['port'])):
return public.returnMsg(False, "Port %s is occupied, repair failed" % str(project_config['port']))
# Check if the path exists
if not os.path.exists(project_info['path']):
os.makedirs(project_info['path'])
public.set_own(project_info['path'], 'www')
# 确定目录存在。先删除目录
domain = project_info['name']
if os.path.exists(self.__site_path + domain):
public.ExecShell('rm -rf ' + self.__site_path + domain)
tomcat_version = project_config['tomcat_version']
# 复制项目
if not os.path.exists(self.__site_path + domain):
public.ExecShell('mkdir -p %s' % self.__site_path + domain)
if tomcat_version == 'tomcat7' or tomcat_version == '7':
if not os.path.exists(self.__tomcat7_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat7 configuration file does not exist, please reinstall Tomcat7"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat7_path_bak, self.__site_path + domain, self.__site_path + domain)
)
if tomcat_version == 'tomcat8' or tomcat_version == '8':
if not os.path.exists(self.__tomcat8_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat8 configuration file does not exist, please reinstall Tomcat8"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat8_path_bak, self.__site_path + domain, self.__site_path + domain)
)
if tomcat_version == 'tomcat9' or tomcat_version == '9':
if not os.path.exists(self.__tomcat9_path_bak + '/conf/server.xml'): return public.returnMsg(
False, "Tomcat9 configuration file does not exist, please reinstall Tomcat9"
)
public.ExecShell(
'cp -r %s/* %s && chown -R www:www %s' % (
self.__tomcat9_path_bak, self.__site_path + domain, self.__site_path + domain)
)
# server.xml
if os.path.exists(self.__site_path + domain + '/conf/server.xml'):
ret = '''<Server port="{}" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector connectionTimeout="20000" port="8083" protocol="HTTP/1.1" redirectPort="8490" />
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" />
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt" />
</Host>
</Engine>
</Service>
</Server>'''.format(self.generate_random_port(), get.project_name.strip())
log_path = "/www/wwwlogs/java/{}".format(get.project_name)
if not os.path.exists(log_path) or os.path.isfile(log_path):
os.makedirs(log_path, mode = 0o777)
public.WriteFile(self.__site_path + domain + '/conf/server.xml', ret)
else:
os.system('rm -rf %s' % self.__site_path + domain)
return public.returnMsg(False, "The configuration file does not exist. Please reinstall Tomcat and try creating a new website")
if not self.Initialization2(tomcat_version, domain):
return public.returnMsg(False, "Configuration file error or service not installed")
# Change the port first
ret = self.set_site_port(str(project_config['port']), tomcat_version, domain)
if not ret['status']: return ret
ret = self.add_vhost(path = project_info['path'], domain = domain)
if ret:
# 启动实例
pid_path = '/www/server/web_site/%s/logs/catalina-daemon.pid' % domain
if os.path.exists(pid_path):
os.remove(pid_path)
public.ExecShell('sh %s' % self.__site_path + domain + '/bin/daemon.sh start')
# 建立反代项目
public.WriteLog(self._log_name, 'Successfully repaired Java project {}'.format(domain))
return public.returnMsg(True, "Repair successful")
if project_config['java_type'] == 'neizhi':
if not os.path.exists(
self.__bttomcat_path + "/tomcat{}/conf/server.xml".format(project_config['tomcat_version'])
): return public.returnMsg(False, 'Failed to repair, the current Tomcat version is not installed')
if not self.Initialization(project_config['tomcat_version']): return public.returnMsg(
False, "Tomcat%s configuration file error or service not installed" % project_config['tomcat_version']
)
if self.add_vhost(path = project_info['path'], domain = project_info['name']):
res = self.stop_project(get)
res = self.start_project(get)
return public.returnMsg(True, 'Repair successful')
else:
if self.get_vhost(project_info['name']):
return public.returnMsg(True, 'Already repaired successfully, please do not submit again')
return public.returnMsg(True, 'Repair failed')
else:
return public.returnMsg(False, 'The project is not a standalone Tomcat project or a built-in Tomcat project')
def get_project_info(self, get):
'''
@name Get specified project information
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<Project Name>
}
@return dict
'''
if not hasattr(get, 'project_name'):
return public.returnMsg(False, 'Please provide the project name!')
project_info = public.M('sites').where('project_type=? AND name=?', ('Java', get.project_name)).find()
if not project_info: return public.returnMsg(False, 'The specified project does not exist!')
project_info = self.get_project_stat(project_info)
return project_info
def get_ssl_end_date(self, project_name):
'''
@name 获取SSL信息
@author hwliang<2021-08-09>
@param project_name <string> 项目名称
@return dict
'''
import data
return data.data().get_site_ssl_info('java_{}'.format(project_name))
def get_project_stat(self, project_info):
'''
@name 获取项目状态信息
@author hwliang<2021-08-09>
@param project_info<dict> 项目信息
@return list
'''
project_info['project_config'] = json.loads(project_info['project_config'])
if "jdk_path" not in project_info['project_config']:
project_info['project_config']["jdk_path"] = "/usr/local/btjdk/jdk8"
project_info["use_project_watch"] = use_project_watch(project_info['name'])
if project_info['project_config']['java_type'] == 'springboot':
project_info['run'] = self.get_project_run_state(project_name = project_info['name'])
project_info['load_info'] = self.get_project_load_info(project_name = project_info['name'])
project_info['ssl'] = self.get_ssl_end_date(project_name = project_info['name'])
project_info['listen'] = []
project_info['listen_ok'] = True
# 远程调试
project_info['debug'] = False
if '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=' in project_info['project_config'][
'project_cmd']:
project_info['debug'] = True
if project_info['load_info']:
for pid in project_info['load_info'].keys():
if not 'connections' in project_info['load_info'][pid]:
project_info['load_info'][pid]['connections'] = []
for conn in project_info['load_info'][pid]['connections']:
if not conn['status'] == 'LISTEN': continue
if not conn['local_port'] in project_info['listen']:
project_info['listen'].append(conn['local_port'])
if project_info['listen']:
project_info['listen_ok'] = project_info['project_config']['port'] in project_info['listen']
return project_info
if project_info['project_config']['java_type'] == 'duli':
project_info['run'] = self.get_duli_run_state(project_name = project_info['name'])
project_info['load_info'] = self.get_duli_load_info(project_name = project_info['name'])
project_info['ssl'] = self.get_ssl_end_date(project_name = project_info['name'])
project_info['tomcat_info'] = self.pendent_tomcat_info(domain = project_info['name'])
project_info['listen'] = []
project_info['listen_ok'] = True
if project_info['load_info']:
for pid in project_info['load_info'].keys():
for conn in project_info['load_info'][pid]['connections']:
if not conn['status'] == 'LISTEN': continue
if not conn['local_port'] in project_info['listen']:
project_info['listen'].append(conn['local_port'])
if project_info['listen']:
project_info['listen_ok'] = project_info['project_config']['port'] in project_info['listen']
return project_info
if project_info['project_config']['java_type'] == 'neizhi':
project_info['run'] = self.get_duli_run_state(
project_name = project_info['name'],
bt_tomcat_web = '/usr/local/bttomcat/tomcat{}'.format(project_info['project_config']['tomcat_version']),
neizhi = True
)
project_info['load_info'] = self.get_duli_load_info(
project_name = project_info['name'],
bt_tomcat_web = '/usr/local/bttomcat/tomcat{}'.format(project_info['project_config']['tomcat_version']),
neizhi = True
)
project_info['ssl'] = self.get_ssl_end_date(project_name = project_info['name'])
project_info['tomcat_info'] = self.get_tomcat_info(
version = project_info['project_config']['tomcat_version']
)
project_info['listen'] = []
project_info['listen_ok'] = True
if project_info['load_info']:
for pid in project_info['load_info'].keys():
for conn in project_info['load_info'][pid]['connections']:
if not conn['status'] == 'LISTEN': continue
if not conn['local_port'] in project_info['listen']:
project_info['listen'].append(conn['local_port'])
if project_info['listen']:
project_info['listen_ok'] = project_info['project_config']['port'] in project_info['listen']
return project_info
# xss 防御
def xsssec(self, text):
return text.replace('<', '&lt;').replace('>', '&gt;')
def last_lines(self, filename, lines=1):
return public.GetNumLines(filename, lines)
def get_project_log_old(self, get):
'''
@name 取项目日志
@author lkq<2021-08-27>
@param domain 域名
@param project_name 项目名称
@return string
'''
project_info = self.get_project_find(get.project_name.strip())
if not project_info: return public.returnMsg(False, 'The specified project does not exist!')
if project_info['project_config']['java_type'] == 'springboot':
# log_file = "{}/{}.log".format(self._springboot_logs_path,get.project_name)
log_file = project_info['project_config']['logs']
if not os.path.exists(log_file): return public.returnMsg(False, 'The log file does not exist!')
log_file_size = os.path.getsize(log_file)
return {
"status": True,
"path": log_file.rsplit("/", 1)[0],
"size": public.to_size(log_file_size),
"data": self.xsssec(public.GetNumLines(log_file, 3000)) if log_file_size < 3145928 else self.xsssec(
self.last_lines(log_file, 3000)
)
}
if project_info['project_config']['java_type'] == 'duli':
log_file = '/www/server/bt_tomcat_web/{}/logs/catalina-daemon.out'.format(get.project_name.strip())
log_file_size = os.path.getsize(log_file)
return {
"status": True,
"path": log_file.rsplit("/", 1)[0],
"size": public.to_size(log_file_size),
"data": self.xsssec(public.GetNumLines(log_file, 3000)) if log_file_size < 3145928 else self.xsssec(
self.last_lines(log_file, 3000)
)
}
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
log_file = '/usr/local/bttomcat/tomcat%s/logs/catalina-daemon.out' % version
log_file_size = os.path.getsize(log_file)
return {
"status": True,
"path": log_file.rsplit("/", 1)[0],
"size": public.to_size(log_file_size),
"data": self.xsssec(public.GetNumLines(log_file, 3000)) if log_file_size < 3145928 else self.xsssec(
self.last_lines(log_file, 3000)
)
}
def get_project_log(self, get):
'''
@name 取项目日志
@author lkq<2021-08-27>
@param domain 域名
@param project_name 项目名称
@return string
'''
try:
from mod.project.java.utils import site_tomcat, bt_tomcat
except:
site_tomcat = bt_tomcat = None
project_info = self.get_project_find(get.project_name.strip())
if not project_info: return public.returnMsg(False, 'The specified project does not exist!')
if project_info['project_config']['java_type'] == 'springboot':
log_file = project_info['project_config']['logs']
# if log_file.startswith(self._springboot_logs): return self.get_project_log_old(get)
if not os.path.exists(log_file):
# return public.returnMsg(False, 'The log file does not exist!')
log_file_size = 0
else:
log_file_size = os.path.getsize(log_file)
_path = log_file.rsplit("/", 1)[0]
if log_file_size > 3145928:
return {
"status": True,
"path": _path,
"file": log_file,
"data": self.xsssec(self.last_lines(log_file, 3000)),
"size": public.to_size(log_file_size)
}
return {
"status": True,
"path": _path,
"file": log_file,
"data": self.xsssec(public.GetNumLines(log_file, 3000)),
"size": public.to_size(log_file_size)
}
if project_info['project_config']['java_type'] == 'duli':
if not "logs" in project_info['project_config']: return self.get_project_log_old(get)
log_file = log_path = None
if site_tomcat:
tomcat_name = project_info['project_config'].get("tomcat_name", "")
if tomcat_name:
tomcat = site_tomcat(tomcat_name)
else:
tomcat = site_tomcat(get.project_name.strip())
if tomcat:
log_file = tomcat.log_file
log_path = os.path.dirname(log_file) + "/"
if log_file is None:
log_path = project_info['project_config']['logs']
if log_path[-1] != "/":
log_path = log_path + "/"
log_file = '{}catalina-daemon-{}.out'.format(log_path, project_info["name"].replace(".", "_"))
if not os.path.isfile(log_file):
log_file_size = 0
else:
log_file_size = os.path.getsize(log_file)
return {
"status": True,
"path": log_path[:-1],
"file": log_file,
"size": public.to_size(log_file_size),
"data": self.xsssec(public.GetNumLines(log_file, 3000)) if log_file_size < 3145928 else self.xsssec(
self.last_lines(log_file, 3000)
)
}
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
res = public.ExecShell('sed -n "142p" /usr/local/bttomcat/tomcat{}/bin/daemon.sh'.format(version))[0]
if res.find('test ".$CATALINA_OUT" = . && CATALINA_OUT="$CATALINA_BASE/logs/catalina-daemon.out"') == 0:
return self.get_project_log_old(get)
log_file = None
if bt_tomcat:
tomcat = bt_tomcat(version)
if tomcat:
log_file = tomcat.log_file
if log_file is None:
try:
log_file = public.readFile(
"/usr/local/bttomcat/tomcat%s/conf/logpath.conf" % version
) + f'/catalina-daemon-{version}.out'
except:
log_file = '/www/wwwlogs/java/neizhi%s/catalina-daemon.out' % version
if not os.path.exists(log_file):
log_file_size = 0
else:
log_file_size = os.path.getsize(log_file)
return {
"status": True,
"path": log_file.rsplit("/", 1)[0],
"file": log_file,
"size": public.to_size(log_file_size),
"data": self.xsssec(public.GetNumLines(log_file, 3000)) if log_file_size < 3145928 else self.xsssec(
self.last_lines(log_file, 3000)
)
}
def remove_project(self, get):
'''
@name 删除指定项目
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name: string<项目名称>
}
@return dict
'''
if not 'project_name' in get: return public.returnMsg(False, 'Please provide the project name!')
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The specified project does not exist: {}'.format(get.project_name))
if not project_find: return public.returnMsg(False, 'The specified project does not exist!')
if not project_find['project_config']: return public.returnMsg(False, 'The specified project does not exist!')
if not project_find['project_config']['java_type']: return public.returnMsg(False, 'The specified project does not exist!')
if project_find['project_config']['java_type'] == 'duli':
# 关闭独立项目
get.domain = project_find['name']
get.type = 'stop'
self.pendent_tomcat_start(get)
# 删除项目
self.clear_config(get.project_name)
public.M('domain').where('pid=?', (project_find['id'],)).delete()
public.M('sites').where('name=?', (get.project_name,)).delete()
public.ExecShell("rm -rf %s/%s" % (self.__site_path, project_find['name']))
public.WriteLog(self._log_name, 'Deleted Java project {}'.format(get.project_name))
for i in project_find['project_config']['domains']:
self.del_hosts(i)
self.del_crontab(get.project_name)
# self.remove_sites_service_config(get.project_name)
return public.returnMsg(True, 'Project deleted successfully')
elif project_find['project_config']['java_type'] == 'neizhi':
# Delete tomcat site
self.tomcat_vhost_delete(project_find['project_config']['tomcat_version'], project_find['project_config']['domains'], get)
self.clear_config(get.project_name)
public.M('domain').where('pid=?', (project_find['id'],)).delete()
public.M('sites').where('name=?', (get.project_name,)).delete()
public.WriteLog(self._log_name, 'Deleted Java project {}'.format(get.project_name))
# Restart tomcat
get.version = project_find['project_config']['tomcat_version']
get.type = 'reload'
# self.start_tomcat(get)
# 删除hosts
# self.del_hosts(get.project_name)
# 获取域名列表
for i in project_find['project_config']['domains']:
self.del_hosts(i)
self.del_crontab(get.project_name)
# self.remove_sites_service_config(get.project_name)
return public.returnMsg(True, 'Project deleted successfully')
elif project_find['project_config']['java_type'] == 'springboot':
# 停止项目
self.stop_project(get)
# 删除项目
self.clear_config(get.project_name)
public.M('domain').where('pid=?', (project_find['id'],)).delete()
public.M('sites').where('name=?', (get.project_name,)).delete()
pid_file = project_find['project_config']['pids']
if os.path.exists(pid_file): os.remove(pid_file)
script_file = project_find['project_config']['scripts']
if os.path.exists(script_file): os.remove(script_file)
log_file = project_find['project_config']['logs']
if os.path.exists(log_file): os.remove(log_file)
public.WriteLog(self._log_name, 'Deleted Java project {}'.format(get.project_name))
for i in project_find['project_config']['domains']:
self.del_hosts(i)
self.del_crontab(get.project_name)
# self.remove_sites_service_config(get.project_name)
return public.returnMsg(True, 'Project deleted successfully')
else:
return public.returnMsg(False, 'Invalid project type')
def modify_project(self, get):
'''
@name 修改指定项目
@author hwliang<2021-08-09>
@param get<dict_obj>{
project_name : string<项目名称>
}
@return dict
'''
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.return_error('The specified project does not exist: {}'.format(get.project_name))
# springboot项目能修改端口 运行用户 开机启动 JDK jar 启动命令 项目名称
if project_find['project_config']['java_type'] == 'springboot':
return self.modify_project_springboot(get, project_find = project_find)
if project_find['project_config']['java_type'] == 'duli':
return self.modify_project_duli(get, project_find = project_find)
if project_find['project_config']['java_type'] == 'neizhi':
return self.modify_project_neizhi(get, project_find = project_find)
return public.returnMsg(False, 'Invalid project type')
def modify_project_springboot(self, get, project_find):
'''
@修改springboot 项目配置
@param get.port 修改的端口号
@param get.run_user 运行目录
@param get.auth 开机自启动
@param get.project_jdk 项目JDK
@param get.project_jar 项目jar
@param get.project_ps 项目描述
@param get.project_move_name 项目名称
'''
if hasattr(get, 'project_move_name'):
if get.project_move_name.strip() != get.project_name.strip():
project_name = get.project_move_name.strip()
else:
project_name = get.project_name.strip()
else:
project_name = get.project_name.strip()
project_find['project_config']['project_name'] = project_name
if hasattr(get, 'port'):
if hasattr(get, 'port'):
try:
int(get.port)
except:
return public.returnMsg(False, "Invalid port parameter")
if int(project_find['project_config']['port']) != int(get.port):
if self.check_port_is_used(get.get('port/port'), True):
return public.returnMsg(
False, 'The specified port is already in use by another application. Please modify your project configuration to use a different port, Port: {}'.format(
get.port
)
)
project_find['project_config']['port'] = int(get.port)
if hasattr(get, 'auth'): project_find['project_config']['auth'] = get.auth
if hasattr(get, 'run_user'): project_find['project_config']['run_user'] = get.run_user
if hasattr(get, 'project_jdk'): project_find['project_config']['project_jdk'] = get.project_jdk.strip()
if hasattr(get, 'project_jar'): project_find['project_config']['project_jar'] = get.project_jar.strip()
if hasattr(get, 'project_cmd'):
project_find['project_config']['project_cmd'] = get.project_cmd.strip()
else:
return public.returnMsg(False, 'Missing project_cmd parameter')
# Check if the jar file is in the cmd
if project_find['project_config']['project_cmd'].find(get.project_jar.strip()) == -1:
return public.returnMsg(False, 'The project jar file name is not in the project startup command, please check')
if hasattr(get, 'project_jar'):
project_path = os.path.dirname(get.project_jar.strip())
project_find['project_config']['jar_path'] = project_path
if hasattr(get, 'jmx_status') and hasattr(get, "jmx_port"):
jmx_url = "service:jmx:rmi:///jndi/rmi://127.0.0.1:{}/jmxrmi".format(get.jmx_port)
project_find['project_config']['jmx_status'] = get.jmx_status
project_find['project_config']['jmx_info'] = {
"jmx_url": jmx_url,
"username": "",
"password": "",
}
pdata = {
'name': project_name,
'path': get.project_jar.strip(),
'ps': get.project_ps.strip(),
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
self.set_config(get.project_name)
# 重启项目
# return self.restart_project(get)
res = self.stop_project(get)
res = self.start_project(get)
if "use_project_watch" in get and get.use_project_watch in ("1", "true", "yes", 1):
add_project_watch(
p_name = get.project_name.strip(),
p_type = "java",
site_id = project_find["id"],
watch_path = get.project_jar.strip()
)
else:
del_project_watch(get.project_name.strip())
public.WriteLog(self._log_name, 'Modified Java project {}'.format(get.project_name))
return public.returnMsg(True, 'Project modified successfully')
def modify_project_duli(self, get, project_find):
'''
@修改独立项目配置
@param get.project_name 项目名称
@param get.project_path 项目路径
@param get.port 修改的端口号
@param get.project_ps 项目描述
@param get.tomcat_start tomcat启动脚本路径
@param get.jdk_path 更换JDK的路径
'''
falg = False
if hasattr(get, 'port'):
if int(project_find['project_config']['port']) != int(get.port):
if self.check_port_is_used(get.get('port/port'), True):
return public.returnMsg(
False, 'The specified port is already in use by another application. Please modify your project configuration to use a different port, Port: {}'.format(
get.port
)
)
project_find['project_config']['port'] = int(get.port)
# 独立项目修改端口
ret = self.set_tomcat_duli_port(get, get_project_find = project_find)
falg = True
if not ret['status']: return ret
# 更换项目路径
if hasattr(get, 'project_path'):
if (get.project_path.strip() == project_find['path']):
pass
else:
ret = self.set_tomcat_duli_path(get, get_project_find = project_find)
falg = True
if not ret['status']: return ret
# 更换JDK
if hasattr(get, 'jdk_path'):
ret = self.change_duli_tomcat_jdk(get.project_name, get.jdk_path)
if not ret['status']:
return ret
# ret = self.pendent_tomcat_info(domain=get.project_name)
# if ret['jdk_path']:
# if ret['jdk_path'] != get.jdk_path.strip():
# # 验证当前JDK是否可用
# if not os.path.exists(ret['jdk_path']):
# return public.returnMsg(False, '当前JDK不可用')
# # 验证JDK是否存在
# ret2 = self.replace_jdk_version(get)
# falg = True
# if not ret2['status']:
# # 恢复到之前的JDK
# get.jdk_path = ret['jdk_path']
# self.replace_jdk_version(get)
# return ret2
# 开机自启动
if hasattr(get, 'auth'):
if str(get.auth) != str(project_find['project_config']['auth']):
project_find['project_config']['auth'] = get.auth
falg = True
pdata = {
'project_config': json.dumps(project_find['project_config'])
}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
# 更换描述
if hasattr(get, 'project_ps'):
if get.project_ps.strip() != project_find['ps']:
falg = True
pdata = {'ps': get.project_ps.strip()}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
if falg:
self.set_config(get.project_name)
# self.restart_project(get)
self.stop_project(get)
self.start_project(get)
return public.returnMsg(True, 'Project modification completed')
def modify_project_neizhi(self, get, project_find):
'''
@name 修改内置项目配置
@param get.project_name 项目名称
@param get.port 修改的端口号
@param get.project_ps 项目描述
@param get.tomcat_start tomcat启动脚本路径
@param get.jdk_path 更换JDK的路径
'''
flag = False
if hasattr(get, 'port'):
if int(project_find['project_config']['port']) != int(get.port):
if self.check_port_is_used(get.get('port/port'), True):
return public.returnMsg(
False, 'The specified port is already occupied by another application. Please modify your project configuration to use a different port: {}'.format(
get.port
)
)
project_find['project_config']['port'] = int(get.port)
# 独立项目修改端口
flag = True
ret = self.set_tomcat_duli_port(get, get_project_find = project_find)
if not ret['status']: return ret
# 更换JDK
if hasattr(get, 'jdk_path'):
ret = self.pendent_tomcat_info(domain = get.project_name)
if ret['jdk_path']:
if ret['jdk_path'] != get.jdk_path.strip():
# 验证当前JDK是否可用
flag = True
if not os.path.exists(ret['jdk_path']):
return public.returnMsg(False, 'The current JDK is unavailable')
# 验证JDK是否存在
ret2 = self.replace_jdk_version(get)
if not ret2['status']:
# 恢复到之前的JDK
get.jdk_path = ret['jdk_path']
self.replace_jdk_version(get)
return ret2
# 更换项目路径
if hasattr(get, 'project_path'):
if (get.project_path.strip() == project_find['path']):
pass
else:
ret = self.set_tomcat_duli_path(get, get_project_find = project_find)
flag = True
if not ret['status']: return ret
# 更换描述
if hasattr(get, 'project_ps'):
if get.project_ps.strip() != project_find['ps']:
flag = True
pdata = {'ps': get.project_ps.strip()}
public.M('sites').where('name=?', (get.project_name,)).update(pdata)
if flag:
self.set_config(get.project_name)
self.restart_project(get)
return public.returnMsg(True, "Project modified successfully")
def auto_run(self):
'''
@name 自动启动所有项目
@author hwliang<2021-08-09>
@return bool
'''
project_list = public.M('sites').where('project_type=?', ('Java',)).field('name,path,project_config').select()
get = public.dict_obj()
success_count = 0
error_count = 0
for project_find in project_list:
project_config = json.loads(project_find['project_config'])
if project_config['auth'] in [0, False, '0', None]: continue
project_name = project_find['name']
if project_config['java_type'] == 'springboot':
project_state = self.get_project_run_state(project_name = project_name)
elif project_config['java_type'] == 'duli':
project_state = self.get_duli_run_state(project_name = project_name)
else:
get.project_name = project_name
project_state = self.get_duli_run_state(
project_name = project_name,
bt_tomcat_web = '/usr/local/bttomcat/tomcat{}'.format(
project_config['tomcat_version']
), neizhi = True
)
if not project_state:
get.project_name = project_name
result = self.start_project(get)
if not result['status']:
error_count += 1
error_msg = 'Automatically start Java projects [' + project_name + '] failed!'
public.WriteLog(self._log_name, error_msg)
else:
success_count += 1
success_msg = 'Automatically start Java projects [' + project_name + '] succeeded!'
public.WriteLog(self._log_name, success_msg)
if (success_count + error_count) < 1: return False
dene_msg = 'A total of {} Java projects need to be started, {} succeeded, {} failed'.format(
success_count + error_count, success_count, error_count
)
public.WriteLog(self._log_name, dene_msg)
return True
def get_jmap_path(self, project_find):
'''
@name 获取jmap jhat jstack绝对路径
@author lkq<2021-09-24>
@return list
'''
# 获取当前的jdk路径
ret = {}
cmd = project_find['project_config']['project_cmd']
if not cmd:
return False
# 获取java的绝对路径
cmd = cmd.split()
path = None
for i in cmd:
if 'bin/java' in i:
path = i
break
if not path:
jdk_list = self.get_local_jdk_version(None)
if jdk_list:
path = '/'.join(jdk_list[0][1].split('/')[:-1])
jmap_path = path + '/jmap'
if os.path.exists(jmap_path):
ret['jmap'] = jmap_path
if os.path.exists(path + '/jhat'):
ret['jhat'] = path + '/jhat'
if os.path.exists(path + '/jstack'):
ret['jstack'] = path + '/jstack'
return ret
else:
path = '/'.join(path.split('/')[:-1])
jmap_path = path + '/jmap'
if os.path.exists(jmap_path):
ret['jmap'] = jmap_path
if os.path.exists(path + '/jhat'):
ret['jhat'] = path + '/jhat'
if os.path.exists(path + '/jstack'):
ret['jstack'] = path + '/jstack'
return ret
def get_project_dump(self, get):
'''
@name 获取heapdump 文件列表
@author lkq<2021-09-24>
@return list
'''
ret = []
project_find = self.get_project_find(get.project_name)
if not project_find:
return ret
if not project_find['project_config']['java_type'] == 'springboot': return ret
if not os.path.exists(self._springoot_dump + '/' + get.project_name + '.json'): return ret
try:
ret = json.loads(public.ReadFile(self._springoot_dump + '/' + get.project_name + '.json'))
return ret
except:
public.WriteFile(public.ReadFile(self._springoot_dump + '/' + get.project_name + '.json'), [])
return ret
def del_project_dump(self, get):
'''
@name 获取heapdump 文件列表
@author lkq<2021-09-24>
@param get.project_name 项目名称
@param get.dump_name 文件名称
'''
ret = []
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The project does not exist')
if not project_find['project_config']['java_type'] == 'springboot': return public.returnMsg(
False, 'Only SpringBoot projects are supported'
)
if not os.path.exists(self._springoot_dump + '/' + get.project_name + '.json'): return public.returnMsg(
False, 'The path does not exist in the current project'
)
if not os.path.exists(get.dump_name.strip()): return public.returnMsg(False, 'The file does not exist')
try:
ret = json.loads(public.ReadFile(self._springoot_dump + '/' + get.project_name + '.json'))
if get.dump_name.strip() in ret:
ret.remove(get.dump_name.strip())
public.ExecShell("rm -rf %s" % get.dump_name.strip())
return public.returnMsg(True, 'Deletion successful')
except:
public.WriteFile(public.ReadFile(self._springoot_dump + '/' + get.project_name + '.json'), [])
return public.returnMsg(True, 'Deletion successful')
def heapdump_project(self, get):
'''
@name 生成headdump 文件
@author lkq<2021-09-24>
@param type Finfo 代表强制获取每个类占用 info获取每个类占用 dump生成dump文件 Fdump 强制生成dump文件 heap 显示Java堆详细信息 Fheap 强制显示Java堆详细信息
@return list
'''
if not hasattr(get, 'type'):
get.type = 'info'
type = get.type
else:
type = get.type
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The specified project does not exist 2: {}'.format(get.project_name))
if not project_find['project_config']['java_type'] == 'springboot': return public.returnMsg(
False, 'Only Springboot projects are supported'
)
# 获取jmap jhat jstack绝对路径
path = self.get_jmap_path(project_find)
# 获取运行状态
if not self.get_project_run_state(project_name = get.project_name):
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
# 获取pid
pidlist = self.get_project_load_info(project_name = get.project_name)
if not pidlist:
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
pid = 0
for i in pidlist:
pid = i
break
if pid == 0:
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
if 'jmap' in path:
jmap_path = path['jmap']
if type == 'Finfo':
# 强制显示堆中对象的统计信息
cmd = '{} -F -histo {} | head -n 100'.format(jmap_path, pid)
elif type == 'info':
# 显示堆中对象的统计信息
cmd = '{} -histo:live {} | head -n 100'.format(jmap_path, pid)
elif type == 'dump':
path = self._springoot_dump + '/' + str(int(time.time())) + '.dump'
# 生成堆转储快照
cmd = '{} -dump:live,format=b,file={} {}'.format(jmap_path, path, pid)
ret = public.ExecShell(cmd, user = project_find['project_config']['run_user'])
if os.path.exists(path):
if os.path.exists(self._springoot_dump + '/' + get.project_name + '.json'):
try:
ret = json.loads(public.ReadFile(self._springoot_dump + '/' + get.project_name + '.json'))
if path not in ret:
ret.append(path)
public.WriteFile(
self._springoot_dump + '/' + get.project_name + '.json', json.dumps(ret)
)
except:
public.WriteFile(
self._springoot_dump + '/' + get.project_name + '.json', json.dumps([path])
)
else:
public.WriteFile(self._springoot_dump + '/' + get.project_name + '.json', json.dumps([path]))
return public.returnMsg(True, 'Dump file generated successfully. Content: %s' % ret[0])
else:
return public.returnMsg(False, 'Failed to generate dump file. Content: %s' % ret[0])
elif type == 'Fdump':
# 强制生成堆转储快照
cmd = '{} -F -dump:live,format=b,file={} {}'.format(
jmap_path, self._springoot_dump + '/' + time.strftime(
'%Y-%m-%d %X', time.localtime()
) + '.dump', pid
)
ret = public.ExecShell(cmd, user = project_find['project_config']['run_user'])
return public.returnMsg(True, ret)
elif type == 'heap':
# 显示Java堆详细信息
cmd = '{} -heap {} '.format(jmap_path, pid)
elif type == 'Fheap':
# 强制显示Java堆详细信息
cmd = '{} -F -heap {}'.format(jmap_path, pid)
else:
return public.returnMsg(False, 'The specified type does not exist: {}'.format(type))
ret = public.ExecShell(cmd, user = project_find['project_config']['run_user'])
return public.returnMsg(True, ret)
return public.returnMsg(False, 'The current JDK does not have jmap')
def jhat_project(self, get):
'''
@name jhat 分析dump文件
@param dump dump文件
@return string
@ps :此功能消耗很大的内存和CPU。請注意使用
'''
pass
dump_path = get.dump
if not os.path.exists(dump_path):
return public.returnMsg(False, 'Dump file does not exist: {}'.format(dump_path))
cmd = 'jhat {}'.format(dump_path)
return cmd
def jstack_project(self, get):
'''
@name jstack 生成虚拟线程快照
@param pid 进程id
@return string
'''
project_find = self.get_project_find(get.project_name)
if not project_find:
return public.returnMsg(False, 'The specified project does not exist 2: {}'.format(get.project_name))
# 获取jmap jhat jstack绝对路径
if not project_find['project_config']['java_type'] == 'springboot': return public.returnMsg(
False, 'Only Springboot projects are supported'
)
path = self.get_jmap_path(project_find)
# 获取运行状态
if not self.get_project_run_state(project_name = get.project_name):
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
# 获取pid
pidlist = self.get_project_load_info(project_name = get.project_name)
if not pidlist:
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
pid = 0
for i in pidlist:
pid = i
break
if pid == 0:
return public.returnMsg(False, 'The specified project is not running: {}'.format(get.project_name))
if 'jstack' in path:
jstack_path = path['jstack']
cmd = '{} -l {}'.format(jstack_path, pid)
# ret=public.ExecShell(cmd,user=project_find['project_config']['run_user'])
ret = public.ExecShell(cmd, user = project_find['project_config']['run_user'])
return public.returnMsg(True, ret)
return public.returnMsg(False, 'The current JDK does not have jstack')
# ————————————
# 批量操作 |
# ————————————
def multi_remove_project(self, get):
'''
@name 批量删除项目
@author baozi<2023-3-2>
@param get<dict_obj>{
project_names: list[string] <项目名称>所组成的列表
}
@return dict
'''
project_names = get.project_names
if isinstance(project_names, list):
pjnames = [i.strip() for i in project_names]
else:
pjnames = []
projects = public.M('sites').where(
f'project_type=? AND name in ({",".join(["?"] * len(pjnames))})',
('Java', *pjnames)
).select()
if not projects:
return public.returnMsg(False, "No sites selected for deletion")
_duli, _neizh, _springboot, _error_type = [], [], [], []
for project in projects:
project['project_config'] = json.loads(project['project_config'])
if project['project_config']['java_type'] == 'duli':
_duli.append(project)
elif project['project_config']['java_type'] == 'neizhi':
_neizh.append(project)
elif project['project_config']['java_type'] == 'springboot':
_springboot.append(project)
else:
_error_type.append("Project:[{}], Invalid project type\n".format(project["name"]))
if _error_type:
return public.return_error(data = _error_type)
# 执行每种删除的独特操作
if _duli:
self._multi_remove_duli(_duli)
if _neizh:
self._multi_remove_neizhi(_neizh)
if _springboot:
self._multi_remove_springboot(_springboot)
# 清除Nginx, Apache 配置文件,并重起服务
self._multi_clear_config(projects)
# 从面板数据库删除信息
project_ids = tuple([i["id"] for i in projects])
public.M('domain').where('pid IN ({})'.format(",".join(["?"] * len(projects))), project_ids).delete()
public.M('sites').where(
f'project_type=? AND name in ({",".join(["?"] * len(pjnames))})',
('Java', *pjnames)
).delete()
public.WriteLog(self._log_name, f'Batch delete Java projects:[{"; ".join([i["name"] for i in projects])}]')
# 获取域名列表 并删除host
for project in projects:
self.del_crontab(project["name"])
for i in project['project_config']['domains']:
self.del_hosts(i)
return {"status": True, "msg": "Delete successful", "project_names": pjnames}
def _multi_clear_config(self, projects):
for project in projects:
self.clear_nginx_config(project)
self.clear_apache_config(project)
public.serviceReload()
def _multi_remove_duli(self, projects):
get = public.dict_obj()
for project in projects:
# 关闭独立项目
get.domain = project['name']
get.type = 'stop'
self.pendent_tomcat_start(get)
# 删除项目
shutil.rmtree(self.__site_path, project['name'])
def _multi_remove_tomcat_vhost(self, projects):
if not self.__ENGINE: return
domains = [project["name"] for project in projects if project["name"] != 'localhost']
try:
Hosts = self.__ENGINE.getchildren()
except:
Hosts = list(self.__ENGINE)
for host in Hosts:
if host.tag != 'Host': continue
if host.attrib['name'] in domains:
self.__ENGINE.remove(host)
self.save_tomcat()
def _multi_remove_neizhi(self, projects):
version_group = {}
res_msg = []
# 按版本分组
for project in projects:
if project['project_config']['tomcat_version'] in version_group:
version_group[project['project_config']['tomcat_version']].append(project)
else:
version_group[project['project_config']['tomcat_version']] = [project, ]
# 处理Tomcat配置文件
for version, group_projects in version_group.items():
if not self.Initialization(version):
res_msg.append(
"Project[{}]".format(",".join([i["name"] for i in group_projects])) + ":Configuration file error, please check the configuration file"
)
continue
self._multi_remove_tomcat_vhost(group_projects)
get = public.dict_obj()
get.version = version
get.type = 'reload'
self.start_tomcat(get)
def _multi_remove_springboot(self, projects):
get = public.dict_obj()
for project in projects:
# 停止项目
get.project_name = project["name"]
self.stop_project(get)
# 删除项目
pid_file = project['project_config']['pids']
if os.path.exists(pid_file): os.remove(pid_file)
script_file = project['project_config']['scripts']
if os.path.exists(script_file): os.remove(script_file)
log_file = project['project_config']['logs']
if os.path.exists(log_file): os.remove(log_file)
def multi_set_project(self, get):
'''
@name 批量设置项目
@author baozi<2023-3-2>
@param get<dict_obj>{
project_names: list[string] <项目名称>所组成的列表
}
@return dict
'''
project_names = get.project_names
set_type = get.operation
if set_type not in ["start", "stop"]:
return public.returnMsg(False, "Invalid operation type")
if isinstance(project_names, list):
pjnames = [i.strip() for i in project_names]
else:
pjnames = []
projects = public.M('sites').where(
f'project_type=? AND name in ({",".join(["?"] * len(pjnames))})',
('Java', *pjnames)
).select()
if not projects:
return public.returnMsg(False, "No sites selected for startup")
neizhi_projects = {'7': False, '8': False, '9': False}
_check = self.get_tomcat_version(None)
if not _check["tomcat7"]["status"]: neizhi_projects.pop("7")
if not _check["tomcat8"]["status"]: neizhi_projects.pop("8")
if not _check["tomcat9"]["status"]: neizhi_projects.pop("9")
springboot_projects = []
duli_projects = []
error_list = []
for project in projects:
project['project_config'] = json.loads(project['project_config'])
if project['project_config']['java_type'] == 'neizhi':
if project['project_config']['tomcat_version'] in neizhi_projects:
neizhi_projects[project['project_config']['tomcat_version']] = True
else:
error_list.append(
{
"project_name": project["name"], "msg": "Startup failed, Tomcat{} is not installed".format(
project['project_config']['tomcat_version']
)
}
)
pjnames.remove(project["name"])
if project['project_config']['java_type'] == 'duli':
duli_projects.append(project)
if project['project_config']['java_type'] == 'springboot':
springboot_projects.append(project)
for tomcat_version, flag in neizhi_projects.items():
if flag:
_get = public.dict_obj()
_get.type = set_type
_get.version = tomcat_version
self.start_tomcat(_get)
for i in springboot_projects:
if set_type == "start":
flag, msg = self.__start_springboot_project(i)
if not flag:
error_list.append({"project_name": i["name"], "msg": msg})
pjnames.remove(i["name"])
else:
self.__stop_springboot_project(i)
for i in duli_projects:
_get = public.dict_obj()
_get.domain = i['name']
_get.type = set_type
self.pendent_tomcat_start(_get)
if error_list:
return {"status": True, "msg": "Some projects failed to start", "error_list": error_list, "project_names": pjnames}
return {"status": True, "msg": "Startup successful" if set_type == "start" else "Shutdown successful", "project_names": pjnames}
# springboot 停止
def __stop_springboot_project(self, project_info):
pid_file = project_info['project_config']['pids']
if not os.path.exists(pid_file): return public.returnMsg(False, 'Project not started')
try:
pid = int(public.readFile(pid_file))
except:
return False, 'Project not started'
pids = self.get_project_pids(pid = pid)
if not pids: return False, 'Project not started'
self.kill_pids(pids = pids)
if os.path.exists(pid_file): os.remove(pid_file)
self.stop_by_user(project_info["id"])
return True, 'Stop successful'
# springboot 启动
def __start_springboot_project(self, project_find):
project_cmd = project_find["project_config"]['project_cmd']
# 前置准备
log_file = project_find["project_config"]['logs']
pid_file = project_find["project_config"]['pids']
nohup_log = ' &>> {log_file}'.format(log_file = log_file)
if not int(project_find["project_config"].get('nohup_log', 1)):
nohup_log = ''
if 'jar_path' in project_find['project_config']:
jar_path = project_find['project_config']['jar_path']
else:
jar_path = '{}'.format(self._springboot)
# 启动脚本
start_cmd = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
cd {jar_path}
nohup {project_cmd}{nohup_log} &
echo $! > {pid_file}
'''.format(
jar_path = jar_path,
project_cmd = project_cmd,
pid_file = pid_file,
log_file = log_file,
nohup_log = nohup_log,
)
script_file = project_find["project_config"]['scripts']
# 写入启动脚本
public.writeFile(script_file, start_cmd)
if os.path.exists(pid_file): os.remove(pid_file)
public.ExecShell("chmod -R 777 /var/tmp/springboot/")
# public.ExecShell("chown -R {}:{} {}".format(project_find['project_config']['run_user'],project_find['project_config']['run_user'],self._springboot))
public.set_mode(script_file, 755)
public.ExecShell(
"chown {}:{} {}".format(
project_find['project_config']['run_user'], project_find['project_config']['run_user'],
project_find['path']
)
)
# 判断是否在/www/ /www/wwwroot
# 执行脚本文件
p = public.ExecShell(
"bash {}".format(script_file), user = project_find['project_config']['run_user'], env = os.environ.copy()
)
time.sleep(1)
if not os.path.exists(pid_file):
return False, 'Startup failed, please try switching the startup user'
# 获取PID
try:
pid = int(public.readFile(pid_file))
except:
return False, 'Startup failed'
time.sleep(0.4)
pids = self.get_project_pids(pid = pid)
# if not pids:
# if os.path.exists(pid_file): os.remove(pid_file)
# return public.returnMsg(False,'启动失败<br>{}'.format(public.GetNumLines(log_file,20)))
self.start_by_user(project_find["id"])
return True, None
def multi_check_bind_extranet(self, get):
"""检查是否可以绑定外网,并执行绑定操作
@author baozi <202-03-2>
@param:
get ( dict ): project_names 要操作的网站列表
@return
"""
if not public.is_apache_nginx(): return public.returnMsg(False, 'Please install Apache or Nginx first!')
project_names = get.project_names
if isinstance(project_names, list):
pjnames = [i.strip() for i in project_names]
else:
pjnames = []
projects = public.M('sites').where(
f'project_type=? AND name in ({",".join(["?"] * len(pjnames))})', ('Java', *pjnames)
).select()
if not projects:
return public.returnMsg(False, "No sites selected for startup")
error_list = []
flag = False
for project in projects:
project['project_config'] = json.loads(project['project_config'])
if not project['project_config']['domains']:
error_list.append({'project_name': project["name"], "msg": 'Please add at least one domain in the "Domain Management" section'})
pjnames.remove(project["name"])
continue
if "bind_extranet" in project['project_config'] and project['project_config']['bind_extranet'] == 1:
continue
else:
flag = True
project['project_config']['bind_extranet'] = 1
public.M('sites').where("id=?", (project['id'],)).setField(
'project_config', json.dumps(project['project_config'])
)
self.set_nginx_config(project)
self.set_apache_config(project)
public.WriteLog(self._log_name, 'Java project {}, enabled external network mapping'.format(project))
if flag:
public.serviceReload()
if error_list:
return {
"status": True, "msg": "Some sites failed to enable external network mapping", "error_list": error_list, "project_names": pjnames
}
return {"status": True, "msg": "External network mapping enabled successfully", "project_names": pjnames}
def _change_daemom_sh(self, target_sh, logpath, suffix=''):
if not os.path.exists(target_sh): return False
file = public.readFile(target_sh)
rep = r'''\n ?test ?"\.\$CATALINA_OUT" ?= ?\. && {0,3}CATALINA_OUT="[^\n]*"[^\n]*\n'''
repl = f'\ntest ".$CATALINA_OUT" = . && CATALINA_OUT="{logpath}/catalina-daemon{"-" + suffix if suffix else ""}.out"\n'
file = re.sub(rep, repl, file)
public.writeFile(target_sh, file)
return True
def change_log_path(self, get):
""""修改日志文件地址
@author baozi <202-03-13>
@param:
get ( dict ): 请求: 包含项目名称和新的路径
@return
"""
project_info = self.get_project_find(get.project_name.strip())
if not project_info: return public.returnMsg(False, 'Project does not exist')
new_log_path = get.path.strip() if "path" in get else None
if not new_log_path or new_log_path[0] != "/":
return public.returnMsg(False, "Invalid path")
if new_log_path[-1] == "/": new_log_path = new_log_path[:-1]
if not os.path.exists(new_log_path):
os.makedirs(new_log_path, mode = 0o777)
if project_info['project_config']['java_type'] == 'springboot':
project_info['project_config']['logs'] = new_log_path + '/' + project_info["name"] + '.log'
pdata = {
'name': project_info["name"],
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (get.project_name.strip(),)).update(pdata)
# 重启项目
# return self.restart_project(get)
res = self.stop_project(get)
res = self.start_project(get)
public.WriteLog(self._log_name, 'Modified Java project {}'.format(get.project_name))
return public.returnMsg(True, "Project log path modified successfully")
if project_info['project_config']['java_type'] == 'duli':
project_info['project_config']['logs'] = new_log_path + '/'
if not self._change_daemom_sh(
self.__site_path + project_info["name"] + "/bin/daemon.sh", new_log_path,
project_info["name"].replace(".", "_")
):
return public.returnMsg(False, "Failed to modify project log path")
pdata = {
'name': project_info["name"],
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (get.project_name.strip(),)).update(pdata)
# 重启项目
# return self.restart_project(get)
res = self.stop_project(get)
res = self.start_project(get)
public.WriteLog(self._log_name, 'Modified Java project {}'.format(get.project_name))
return public.returnMsg(True, "Project log path modified successfully")
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
if not self._change_daemom_sh(
"/usr/local/bttomcat/tomcat%s/bin/daemon.sh" % version, new_log_path, str(version)
):
return public.returnMsg(False, "Failed to modify project log path")
public.writeFile("/usr/local/bttomcat/tomcat%s/conf/logpath.conf" % version, new_log_path)
res = self.stop_project(get)
res = self.start_project(get)
public.WriteLog(self._log_name, 'Modified Java-Tomcat{} internal project path successfully'.format(version))
return public.returnMsg(True, "Project log path modified successfully")
def for_split(self, logsplit, project):
"""日志切割方法调用
@author baozi <202-03-20>
@param:
logsplit ( LogSplit ): 日志切割方法,传入 pjanme:项目名称 sfile:日志文件路径 log_prefix:产生的日志文件前缀
project ( dict ): 项目内容
@return
"""
try:
from mod.project.java.utils import site_tomcat, bt_tomcat
except:
site_tomcat = bt_tomcat = None
log_file = None
if project['project_config']['java_type'] == 'springboot':
log_file = project['project_config']['logs']
logsplit(project["name"], log_file, project["name"])
return
elif project['project_config']['java_type'] == 'duli':
if site_tomcat:
tomcat_name = project["project_config"].get("tomcat_name", "")
tomcat = site_tomcat(tomcat_name) if tomcat_name else site_tomcat(project["project_config"]["project_name"])
if tomcat:
log_file = tomcat.log_file
if log_file is None:
_log_file = project['project_config']['logs']
log_file = '{}catalina-daemon-{}.out'.format(_log_file, project["name"].replace(".", "_"))
if project['project_config']['java_type'] == 'neizhi':
version = str(project['project_config']['tomcat_version']).split(".")[0]
if bt_tomcat:
tomcat = bt_tomcat(version)
if tomcat:
log_file = tomcat.log_file
if log_file is None:
try:
log_file = public.readFile(
"/usr/local/bttomcat/tomcat%s/conf/logpath.conf" % version
) + f'/catalina-daemon-{version}.out'
except:
log_file = '/www/wwwlogs/java/neizhi%s/catalina-daemon.out' % version
logsplit(project["name"], log_file, project["name"])
# —————————————
# 日志切割 |
# —————————————
def del_crontab(self, name):
"""
@name 删除项目日志切割任务
@auther hezhihong<2022-10-31>
@return
"""
cron_name = f'[Do not delete] Java project [{name}] log rotation'
cron_path = public.GetConfigValue('setup_path') + '/cron/'
cron_list = public.M('crontab').where("name=?", (cron_name,)).select()
if cron_list:
for i in cron_list:
if not i: continue
cron_echo = public.M('crontab').where("id=?", (i['id'],)).getField('echo')
args = {"id": i['id']}
import crontab
crontab.crontab().DelCrontab(args)
del_cron_file = cron_path + cron_echo
public.ExecShell("crontab -u root -l| grep -v '{}'|crontab -u root -".format(del_cron_file))
def add_crontab(self, name, log_conf, python_path):
"""
@name 构造站点运行日志切割任务
"""
cron_name = f'[Do not delete] Java project [{name}] log rotation'
if not public.M('crontab').where('name=?', (cron_name,)).count():
cmd = '{pyenv} {script_path} {name}'.format(
pyenv = python_path,
script_path = self.__log_split_script_py,
name = name
)
args = {
"name": cron_name,
"type": 'day' if log_conf["log_size"] == 0 else "minute-n",
"where1": "" if log_conf["log_size"] == 0 else log_conf["minute"],
"hour": log_conf["hour"],
"minute": log_conf["minute"],
"sName": name,
"sType": 'toShell',
"notice": '0',
"notice_channel": '',
"save": str(log_conf["num"]),
"save_local": '1',
"backupTo": '',
"sBody": cmd,
"urladdress": ''
}
import crontab
res = crontab.crontab().AddCrontab(args)
if res and "id" in res.keys():
return True, "New task created successfully"
return False, res["msg"]
return True
def change_cronta(self, name, log_conf):
"""
@name 更改站点运行日志切割任务
"""
python_path = "/www/server/panel/pyenv/bin/python3"
if not python_path: return False
cronInfo = public.M('crontab').where('name=?', (f'[Do not delete] Java project [{name}] log rotation',)).find()
if not cronInfo:
return self.add_crontab(name, log_conf, python_path)
import crontab
recrontabMode = crontab.crontab()
id = cronInfo['id']
del (cronInfo['id'])
del (cronInfo['addtime'])
cronInfo['sBody'] = '{pyenv} {script_path} {name}'.format(
pyenv = python_path,
script_path = self.__log_split_script_py,
name = name
)
cronInfo['where_hour'] = log_conf['hour']
cronInfo['where_minute'] = log_conf['minute']
cronInfo['save'] = log_conf['num']
cronInfo['type'] = 'day' if log_conf["log_size"] == 0 else "minute-n"
cronInfo['where1'] = '' if log_conf["log_size"] == 0 else log_conf['minute']
columns = 'where_hour,where_minute,sBody,save,type,where1'
values = (
cronInfo['where_hour'], cronInfo['where_minute'], cronInfo['sBody'], cronInfo['save'], cronInfo['type'],
cronInfo['where1'])
recrontabMode.remove_for_crond(cronInfo['echo'])
if cronInfo['status'] == 0: return False, 'The current task is stopped, please start the task before modifying!'
sync_res = recrontabMode.sync_to_crond(cronInfo)
if not sync_res['status']:
return False, sync_res['msg']
public.M('crontab').where('id=?', (id,)).save(columns, values)
public.WriteLog('Scheduled Task', 'Modified scheduled task [' + cronInfo['name'] + '] successfully')
return True, 'Modified successfully'
def mamger_log_split(self, get):
"""Manage log rotation tasks
@author baozi <202-02-27>
@param:
get ( dict ): Contains name, mode, hour, minute
@return
"""
name = get.name.strip()
project = self.get_project_find(name)
if not project:
return public.returnMsg(False, "No such project, please try refreshing the page")
try:
_compress = False
_log_size = float(get.log_size) if float(get.log_size) >= 0 else 0
_hour = get.hour.strip() if 0 <= int(get.hour) < 24 else "2"
_minute = get.minute.strip() if 0 <= int(get.minute) < 60 else '0'
_num = int(get.num) if 0 < int(get.num) <= 1800 else 180
if "compress" in get:
_compress = int(get.compress) == 1
except (ValueError, AttributeError, KeyError):
_log_size = 0
_hour = "2"
_minute = "0"
_num = 180
_compress = False
if _log_size != 0:
_log_size = _log_size * 1024 * 1024
_hour = 0
_minute = 5
log_conf = {
"log_size": _log_size,
"hour": _hour,
"minute": _minute,
"num": _num,
"compress": _compress
}
flag, msg = self.change_cronta(name, log_conf)
if flag:
conf_path = '{}/data/run_log_split.conf'.format(public.get_panel_path())
if os.path.exists(conf_path):
try:
data = json.loads(public.readFile(conf_path))
except:
data = {}
else:
data = {}
data[name] = {
"stype": "size" if bool(_log_size) else "day",
"log_size": _log_size,
"limit": _num,
"compress": _compress
}
public.writeFile(conf_path, json.dumps(data))
project["project_config"]["log_conf"] = log_conf
pdata = {
"project_config": json.dumps(project["project_config"])
}
public.M('sites').where('name=?', (name,)).update(pdata)
return public.returnMsg(flag, msg)
def set_log_split(self, get):
"""设置日志计划任务状态
@author baozi <202-02-27>
@param:
get ( dict ): 包含项目名称name
@return msg : 操作结果
"""
name = get.name.strip()
project_conf = self.get_project_find(name)
if not project_conf:
return public.returnMsg(False, "No such project, please try refreshing the page")
cronInfo = public.M('crontab').where('name=?', (f'[Do not delete] Java project [{name}] log rotation',)).find()
if not cronInfo:
return public.returnMsg(False, "This project has not set up a log rotation task")
status_msg = ['Disabled', 'Enabled']
status = 1
import crontab
recrontabMode = crontab.crontab()
if cronInfo['status'] == status:
status = 0
recrontabMode.remove_for_crond(cronInfo['echo'])
else:
cronInfo['status'] = 1
sync_res = recrontabMode.sync_to_crond(cronInfo)
if not sync_res['status']:
return public.returnMsg(False, sync_res['msg'])
public.M('crontab').where('id=?', (cronInfo["id"],)).setField('status', status)
public.WriteLog('Scheduled Task', 'Modified scheduled task [' + cronInfo['name'] + '] status to [' + status_msg[status] + ']')
return public.returnMsg(True, 'Settings updated successfully')
def get_log_split(self, get):
"""获取站点的日志切割任务
@author baozi <202-02-27>
@param:
get ( dict ): name
@return msg : 操作结果
"""
name = get.name.strip()
project_conf = self.get_project_find(name)
if not project_conf:
return public.returnMsg(False, "No such project, please try refreshing the page")
if self._check_old(project_conf):
return {
"status": False,
"msg": "After updating the version, you need to restart the project to enable the log rotation task. It is recommended to find a suitable time to restart the project.",
"is_old": True
}
cronInfo = public.M('crontab').where('name=?', (f'[Do not delete] Java project [{name}] log rotation',)).find()
if not cronInfo:
return public.returnMsg(False, "This project has not set up a log rotation task")
if "log_conf" not in project_conf["project_config"]:
return public.returnMsg(False, "Log rotation configuration is missing, please try resetting it")
res = project_conf["project_config"]["log_conf"]
res["status"] = cronInfo["status"]
return {"status": True, "data": res}
def _update_project(self, project_name, project_info):
# 检查是否需要更新
# 移动日志文件
# 独立项目需要修改文件
# 内置项目需要修改文件和备份文件
# 保存
if project_info['project_config']['java_type'] == 'springboot':
target_file = "{}/{}.log".format(self._springboot_logs_path, str(project_name))
log_file = project_info['project_config']['logs']
if not log_file.startswith(self._springboot_logs):
return
if os.path.exists(log_file):
self._move_logs(log_file, target_file)
if not os.path.exists(target_file):
return
else:
os.remove(log_file)
project_info['project_config']["logs"] = target_file
pdata = {
'name': project_name,
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (project_name,)).update(pdata)
if project_info['project_config']['java_type'] == 'duli':
if "logs" in project_info['project_config']:
return
_path = '/www/wwwlogs/java/{}/'.format(project_name)
if not os.path.exists(_path):
os.makedirs(_path)
target_file = '{}catalina-daemon-{}.out'.format(_path, project_info["name"].replace(".", "_"))
s_file = '/www/server/bt_tomcat_web/{}/logs/catalina-daemon.out'.format(project_name)
if os.path.exists(s_file):
self._move_logs(s_file, target_file)
if not os.path.exists(target_file):
return
else:
os.remove(s_file)
if not self._change_daemom_sh(
self.__site_path + project_info["name"] + "/bin/daemon.sh", _path[:-1],
project_info["name"].replace(".", "_")
):
return
project_info['project_config']["logs"] = _path
pdata = {
'name': project_name,
'project_config': json.dumps(project_info['project_config'])
}
public.M('sites').where('name=?', (project_name,)).update(pdata)
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
target_file = '/www/wwwlogs/java/neizhi{}/catalina-daemon-{}.out'.format(version, version)
_path = '/www/wwwlogs/java/neizhi{}'.format(version)
if not os.path.exists(_path):
os.makedirs(_path)
s_file = '/usr/local/bttomcat/tomcat%s/logs/catalina-daemon.out' % version
res = public.ExecShell('sed -n "142p" /usr/local/bttomcat/tomcat{}/bin/daemon.sh'.format(version))[0]
if not res.startswith(
'test ".$CATALINA_OUT" = . && CATALINA_OUT="$CATALINA_BASE/logs/catalina-daemon.out"'
):
return
if os.path.exists(s_file):
self._move_logs(s_file, target_file)
if not os.path.exists(target_file):
return
else:
os.remove(s_file)
if not self._change_daemom_sh("/usr/local/bttomcat/tomcat%s/bin/daemon.sh" % version, _path, str(version)):
return
public.writeFile("/usr/local/bttomcat/tomcat%s/conf/logpath.conf" % version, _path)
def _move_logs(self, s_file, target_file):
if os.path.getsize(s_file) > 3145928:
res = self.last_lines(s_file, 3000)
public.WriteFile(target_file, res)
else:
shutil.copyfile(s_file, target_file)
def _check_old(self, project_info):
if project_info['project_config']['java_type'] == 'springboot':
log_file = project_info['project_config']['logs']
if log_file.startswith(self._springboot_logs):
return True
if project_info['project_config']['java_type'] == 'duli':
if not "logs" in project_info['project_config']:
return True
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
_path = '/www/wwwlogs/java/neizhi{}'.format(version)
if not os.path.exists(_path):
os.makedirs(_path)
res = public.ExecShell('sed -n "142p" /usr/local/bttomcat/tomcat{}/bin/daemon.sh'.format(version))[0]
if res.startswith('test ".$CATALINA_OUT" = . && CATALINA_OUT="$CATALINA_BASE/logs/catalina-daemon.out"'):
return True
def _ckeck_add_domain(self, site_name, domains):
from panelSite import panelSite
ssl_data = panelSite().GetSSL(type("get", tuple(), {"siteName": site_name})())
if not ssl_data["status"] or not ssl_data.get("cert_data", {}).get("dns", None):
return {"domains": domains}
domain_rep = []
for i in ssl_data["cert_data"]["dns"]:
if i.startswith("*"):
_rep = "^[^\.]+\." + i[2:].replace(".", "\.")
else:
_rep = "^" + i.replace(".", "\.")
domain_rep.append(_rep)
no_ssl = []
for domain in domains:
if not domain["status"]: continue
for _rep in domain_rep:
if re.search(_rep, domain["name"]):
break
else:
no_ssl.append(domain["name"])
if no_ssl:
return {
"domains": domains,
"not_ssl": no_ssl,
"tip": "This site has enabled SSL certificates, but the newly added domains: {} cannot match the current certificate. If needed, please reapply for the certificate.".format(
str(no_ssl)
)
}
return {"domains": domains}
# 获取 jmx 配置
def get_jmx_config(self, get):
if not hasattr(get, "site_id"):
return public.returnMsg(False, "Missing parameter! site_id")
if not str(get.site_id).isdigit():
return public.returnMsg(False, "Invalid parameter! site_id")
project_config = public.M('sites').where('project_type=? AND id=?', ('Java', get.site_id)).getField(
"project_config"
)
if not project_config:
return public.returnMsg(False, "Website information does not exist!")
# Install jmxquery
try:
from jmxquery import JMXConnection, JMXQuery
except:
public.ExecShell("btpip install jmxquery==0.6.0")
try:
project_config = json.loads(project_config)
except:
project_config = {}
jmx_info = project_config.get("jmx_info", {})
if jmx_info.get("jmx_url") is None:
jmx_info["jmx_url"] = ""
if jmx_info.get("username") is None:
jmx_info["username"] = ""
if jmx_info.get("password") is None:
jmx_info["password"] = ""
return {"status": True, "msg": "ok", "data": jmx_info}
# 设置 jmx 配置
def set_jmx_config(self, get):
if not hasattr(get, "site_id"):
return public.returnMsg(False, "Missing parameter! site_id")
if not str(get.site_id).isdigit():
return public.returnMsg(False, "Invalid parameter! site_id")
jmx_url = getattr(get, "jmx_url")
username = getattr(get, "username", "")
password = getattr(get, "password", "")
project_config = public.M('sites').where('project_type=? AND id=?', ('Java', get.site_id)).getField(
"project_config"
)
if not project_config:
return public.returnMsg(False, "Website information does not exist!")
# 安装 jmxquery
try:
from jmxquery import JMXConnection, JMXQuery
except:
public.ExecShell("btpip install jmxquery==0.6.0")
from jmxquery import JMXConnection
try:
# 创建 JMXConnection
JMXConnection(connection_uri = jmx_url, jmx_username = username, jmx_password = password)
except Exception:
return public.returnMsg(False, "Connection failed!")
try:
project_config = json.loads(project_config)
except:
project_config = {}
jmx_info = {}
if jmx_url:
jmx_info["jmx_url"] = jmx_url
if username:
jmx_info["username"] = username
if password:
jmx_info["password"] = password
project_config["jmx_info"] = jmx_info
public.M('sites').where('project_type=? AND id=?', ('Java', get.site_id,)).update(
{"project_config": json.dumps(project_config)}
)
return public.returnMsg(True, "Configuration set successfully!")
# Get jmx status information
def get_status_info(self, get):
if not hasattr(get, "site_id"):
return public.returnMsg(False, "Missing parameter! site_id")
project_config = public.M('sites').where('project_type=? AND id=?', ('Java', get.site_id)).getField(
"project_config"
)
if not project_config:
return public.returnMsg(False, "Website information does not exist!")
project_config = json.loads(project_config)
if not project_config.get("jmx_status", False):
return public.returnMsg(False, "JMX monitoring is not enabled")
jmx_info = project_config.get("jmx_info")
if jmx_info is None:
return public.returnMsg(False, "Please set up JMX monitoring first")
java_path = project_config.get("project_jdk", '')
jmx_url = jmx_info.get("jmx_url")
username = jmx_info.get("username", "")
password = jmx_info.get("password", "")
if not jmx_url:
return public.returnMsg(False, "JMX monitoring is not set up")
# 安装 jmxquery
try:
from jmxquery import JMXConnection, JMXQuery
except:
public.ExecShell("btpip install jmxquery==0.6.0")
from jmxquery import JMXConnection, JMXQuery
import types
try:
# 替换源库中存在问题的JSON解析函数
def my_load_from_json(the, jsonOutput: str):
if "\n" in jsonOutput:
jsonOutput = jsonOutput.replace("\n", "")
if "\t" in jsonOutput:
jsonOutput = jsonOutput.replace("\t", "")
jsonMetrics = json.loads(jsonOutput)
metrics = []
for jsonMetric in jsonMetrics:
mBeanName = jsonMetric['mBeanName']
attribute = jsonMetric['attribute']
attributeType = jsonMetric['attributeType']
metric_name = None
if 'metricName' in jsonMetric:
metric_name = jsonMetric['metricName']
metric_labels = None
if 'metricLabels' in jsonMetric:
metric_labels = jsonMetric['metricLabels']
attributeKey = None
if 'attributeKey' in jsonMetric:
attributeKey = jsonMetric['attributeKey']
value = None
if 'value' in jsonMetric:
value = jsonMetric['value']
metrics.append(
JMXQuery(mBeanName, attribute, attributeKey, value, attributeType, metric_name, metric_labels)
)
return metrics
# 创建 JMXConnection
# JMX 连接信息
# jmx_host = '127.0.0.1'
# jmx_port = 9001 # 根据你的 Java 程序配置的 JMX 端口修改
# jmx_url = f'service:jmx:rmi:///jndi/rmi://{jmx_host}:{jmx_port}/jmxrmi'
jmxConnection = JMXConnection(
connection_uri = jmx_url, jmx_username = username, jmx_password = password,
java_path = java_path
)
setattr(jmxConnection, "_JMXConnection__load_from_json", types.MethodType(my_load_from_json, jmxConnection))
jmxQuery = [JMXQuery("*:*")]
# 执行查询
metrics = jmxConnection.query(jmxQuery)
except Exception:
return public.returnMsg(False, "Connection failed! {}".format(jmx_url))
# 创建 JMX 查询
jmx_status_info = {}
type_list = ["MemoryPool", "GarbageCollector"]
percent_list = ["SystemCpuLoad", "ProcessCpuLoad"]
microsecond_list = ["StartTime", "Uptime", "endTime", "startTime", "CollectionTime", "CurrentThreadCpuTime",
"CurrentThreadUserTime", "endTime", "startTime", "CollectionTime",
"TotalCompilationTime", ]
nanoseconds_list = ["ProcessCpuTime", ]
size_list = ["FreePhysicalMemorySize", "TotalPhysicalMemorySize", "committed", "init", "max", "used"]
value_dict = {
"True": "是",
"False": "否",
"None": "无",
}
# 解析结果
for metric in metrics:
java_type_obj = re.search("type=([\w\s]+)", metric.mBeanName)
if not java_type_obj:
continue
java_type = java_type_obj.group(1)
name_obj = re.search("name=([\w\s]+)", metric.mBeanName)
name = None
if name_obj:
name = name_obj.group(1)
if jmx_status_info.get(java_type) is None:
if java_type in type_list:
jmx_status_info[java_type] = []
else:
jmx_status_info[java_type] = {}
type_info = jmx_status_info[java_type]
if name is not None:
name = name.replace(" ", "_")
if isinstance(type_info, list):
for info in type_info:
if info["name"] == name:
type_info = info
break
else:
info = {"name": name}
type_info.append(info)
type_info = info
else:
if type_info.get(name) is None:
type_info[name] = {}
type_info = type_info[name]
value = value_dict.get(str(metric.value))
if value is None:
value = metric.value
if metric.attributeKey:
if metric.attribute is not None and type_info.get(metric.attribute) is None:
type_info[metric.attribute] = {}
if value == -1:
value = "Unlimited"
elif metric.attributeKey in size_list:
value = public.to_size(value)
elif metric.attributeKey in microsecond_list:
value = datetime.datetime.fromtimestamp(int(value) / 1000).strftime('%Y-%m-%d %H:%M:%S')
elif metric.attributeKey in nanoseconds_list:
value = "{} seconds".format(int(value) / 1e9)
type_info[metric.attribute][metric.attributeKey] = value
else:
if metric.attribute in size_list:
value = public.to_size(value)
elif metric.attribute in percent_list:
value = "{}%".format(round(int(value) * 100, 2))
elif metric.attribute in microsecond_list:
value = datetime.datetime.fromtimestamp(int(value) / 1000).strftime('%Y-%m-%d %H:%M:%S')
elif metric.attribute in nanoseconds_list:
value = "{} seconds".format(int(value) / 1e9)
type_info[metric.attribute] = value
return {"status": True, "msg": "ok", "data": jmx_status_info}
def get_project_status(self, project_id):
# Only used in project stop alerts
project_info = public.M('sites').where('project_type=? AND id=?', ('Java', project_id)).find()
if not project_info:
return None, ""
project_info["project_config"] = json.loads(project_info["project_config"])
if project_info['project_config']['java_type'] == 'springboot':
if self.is_stop_by_user(project_id):
return True, project_info["name"]
return self.get_project_run_state(project_name = project_info['name']), project_info["name"]
if project_info['project_config']['java_type'] == 'duli':
if self.is_stop_by_user(self.__site_path + "/" + project_info["name"]):
return True, project_info["name"]
return self.get_duli_run_state(project_name = project_info['name']), project_info["name"]
if project_info['project_config']['java_type'] == 'neizhi':
version = project_info['project_config']['tomcat_version']
if self.is_stop_by_user("/etc/init.d/bttomcat{}".format(version)):
return True, project_info["name"]
tomcat_path = '/usr/local/bttomcat/tomcat{}'.format(version)
return self.get_duli_run_state(
project_name = project_info["name"], bt_tomcat_web = tomcat_path,
neizhi = True
), project_info["name"]
def set_jdk_environment(self, get):
# 解析前端发送的数据
jdk_name = get.name
jdk_path = "/www/server/java/{}/bin/java".format(jdk_name)
# 检查提供的JDK路径是否有效
if not os.path.exists(jdk_path):
return "The provided JDK path does not exist."
# 获取JAVA_HOME的新值
new_java_home = os.path.dirname(os.path.dirname(jdk_path))
# 写入全局的shell配置文件
profile_path = '/etc/profile'
java_home_line = "export JAVA_HOME={}".format(new_java_home)
path_line = "export PATH=$JAVA_HOME/bin:$PATH"
# 检查文件是否存在
if os.path.exists(profile_path):
# 读取/etc/profile文件并更新JAVA_HOME和PATH
with open(profile_path, 'r') as file:
lines = file.readlines()
try:
# 检查是否已经设置了JAVA_HOME
with open(profile_path, 'w') as file:
java_home_set = False
for line in lines:
if 'export JAVA_HOME=' in line:
file.write(java_home_line + '\n')
java_home_set = True
elif 'export PATH=$JAVA_HOME/bin:$PATH' in line:
# 如果已经更新了JAVA_HOME,则跳过旧的PATH设置
continue
else:
file.write(line)
if not java_home_set:
# 如果/etc/profile中没有JAVA_HOME设置,则添加它
file.write(java_home_line + '\n')
file.write(path_line + '\n')
public.ExecShell("source /etc/profile")
return public.returnMsg(True, "Set successfully!")
except:
return public.returnMsg(False, "Setting failed, please check if you have enabled system hardening!")
else:
return public.returnMsg(False, "Setting failed!")
def get_system_user_list(self, get):
"""
默认只返回uid>= 1000 的用户 和 root
get中包含 sys_user 返回 uid>= 100 的用户 和 root
get中包含 all_user 返回所有的用户
"""
is_spring_boot = get.get("springboot/d", 0)
if is_spring_boot:
self.set_spring_user()
sys_user = False
all_user = False
if get is not None:
if hasattr(get, "sys_user"):
sys_user = True
if hasattr(get, "all_user"):
all_user = True
user_set = set()
try:
for tmp_uer in pwd.getpwall():
# if is_spring_boot and tmp_uer.pw_shell.find("nologin") != -1:
# continue
if tmp_uer.pw_uid == 0:
user_set.add(tmp_uer.pw_name)
elif tmp_uer.pw_uid >= 1000:
user_set.add(tmp_uer.pw_name)
elif sys_user and tmp_uer.pw_uid >= 100:
user_set.add(tmp_uer.pw_name)
elif all_user:
user_set.add(tmp_uer.pw_name)
except Exception:
pass
return public.return_message(0,0,list(user_set))
def generate_port(self, get):
return public.returnMsg(True, self.generate_random_port())