Linux ip-172-26-2-223 5.4.0-1018-aws #18-Ubuntu SMP Wed Jun 24 01:15:00 UTC 2020 x86_64
Apache
: 172.26.2.223 | : 18.221.70.17
Cant Read [ /etc/named.conf ]
8.1.13
www
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
/
www /
server /
panel /
mod /
project /
java /
[ HOME SHELL ]
Name
Size
Permission
Action
jmxquery
[ DIR ]
drwxr-xr-x
__init__.py
0
B
-rw-r--r--
groupMod.py
42.97
KB
-rw-r--r--
group_script.py
654
B
-rw-r--r--
java_web_conf.py
23.05
KB
-rw-r--r--
projectMod.py
130.9
KB
-rw-r--r--
project_update.py
23.68
KB
-rw-r--r--
server_proxy.py
25
KB
-rw-r--r--
springboot_parser.py
41.01
KB
-rw-r--r--
utils.py
33.33
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : projectMod.py
import itertools import json import re import shutil import sys import os import time import traceback import threading from datetime import datetime import psutil from typing import Dict, List, Optional, Union, Any from mod.base import json_response from mod.base.backup_tool import VersionTool from mod.project.java import utils from mod.base.process import RealUser, RealProcess if "/www/server/panel/class" not in sys.path: sys.path.insert(0, "/www/server/panel/class") import public from projectModel.watchModel import use_project_watch, add_project_watch, del_project_watch from mod.base.web_conf import normalize_domain, is_domain, Redirect, remove_sites_service_config, RealSSLManger from mod.base.web_conf import RealRedirect, RealLogMgr, Proxy, RealProxy from mod.base.process.server import RealServer from mod.project.java.java_web_conf import JvavWebConfig from mod.project.java.server_proxy import RealServerProxy from mod.base.git_tool import GitMager from mod.project.java.springboot_parser import SpringConfigParser, SpringLogConfigParser _DEBUG = True def debug(func): if not _DEBUG: return func def inner(*args, **kwargs): try: return func(*args, **kwargs) except: err = traceback.format_exc() print(err) public.print_log(err) return {"msg": "报错了"} return inner def set_java_service_link(): java_service_bin = '/usr/bin/java-service' java_service_src = '/www/server/panel/script/java-service.py' if os.path.exists(java_service_src): public.ExecShell("chmod 700 " + java_service_src) if not os.path.exists(java_service_bin): if os.path.exists(java_service_src): public.ExecShell("ln -sf {} {}".format(java_service_src, java_service_bin)) set_java_service_link() class main(JvavWebConfig, Proxy, Redirect, GitMager): def __init__(self): super().__init__() self._bt_tomcat_path = "/usr/local/bttomcat" self._mod_tomcat_path = "/usr/local/bt_mod_tomcat" self._bt_jdk_path = "/usr/local/btjdk/" self._java_path = "/www/server/java/" self._vhost_path = "/www/server/panel/vhost" self._java_project_path = "/var/tmp/springboot/" self._java_project_vhost = "/var/tmp/springboot/vhost" self._java_spring_boot_log_path = "/www/wwwlogs/java/springboot" self._site_tomcat_path = '/www/server/bt_tomcat_web/' if not os.path.exists(self._java_project_vhost): os.makedirs(self._java_project_vhost + "/pids", 0o777) os.makedirs(self._java_project_vhost + "/scripts", 0o755) if not os.path.exists(self._java_project_vhost + "/env"): os.makedirs(self._java_project_vhost + "/env", 0o755) if not os.path.exists(self._java_spring_boot_log_path): os.makedirs(self._java_spring_boot_log_path, 0o755) if not os.path.exists(self._site_tomcat_path): os.makedirs(self._site_tomcat_path, 0o755) if not os.path.exists(self._mod_tomcat_path): os.makedirs(self._mod_tomcat_path, 0o755) self._default_java_log = "/www/wwwlogs/java" if not os.path.exists(self._default_java_log): os.makedirs(self._default_java_log, 0o701) # 实现Proxy初始化 Proxy.__init__(self, config_prefix="java_") # 实现Redirect初始化 Redirect.__init__(self, config_prefix="java_") self._real_process: Optional[RealProcess] = None @property def real_process(self) -> RealProcess: if self._real_process is None: self._real_process = RealProcess() return self._real_process @staticmethod def is_stop_by_user(project_id): return utils.is_stop_by_user(project_id) @staticmethod def write_project_log(log_str: str): public.WriteLog("项目管理", log_str) def get_system_info(self, get=None): return json_response(status=True, data={ "jdk_info": self._local_jdk_info(), "tomcat_status": self._bt_tomcat_info(), }) @staticmethod def _local_jdk_info() -> List[Dict]: ret = [] jdk_tool = utils.JDKManager() current_java_home = jdk_tool.get_env_jdk() # 获取已安装的JDK版本 for version in jdk_tool.versions_list: jdk_path = '/www/server/java/' + version + '/bin/java' is_current = os.path.dirname(os.path.dirname(jdk_path)) == current_java_home if os.path.exists('/www/server/java/' + version): ret.append({'name': version, 'path': jdk_path, 'operation': 1, 'is_current': is_current}) else: ret.append({'name': version, 'path': '', 'operation': 0, 'is_current': False}) name = '安装[{}]'.format(version) install_data = public.M('tasks').where("status in (0, -1) and name=?", (name,)).find() if install_data: ret[-1]['operation'] = 3 ret.sort(key=lambda x: (x['operation'] == 1, x['operation'] == 3), reverse=True) # 检查其他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 i in jdk_tool.custom_jdk_list: is_current = utils.normalize_jdk_path(i) == current_java_home ret.append({'name': '自定义JDK', 'path': i, 'operation': 1, 'is_current': is_current}) 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}) return ret @staticmethod def _bt_tomcat_info() -> List[Dict]: versions = [7, 8, 9, 10] data = [] for i in versions: soft_name = "安装[Java项目Tomcat-{}]".format(i) install_data = public.M('tasks').where("status in (0, -1) and name=?", (soft_name,)).find() tmp = utils.bt_tomcat(i).status() tmp["version"] = i if install_data: tmp["is_install"] = True else: tmp["is_install"] = False data.append(tmp) return data @staticmethod def process_for_create(get): is_java_process = True search = '' if hasattr(get, "is_java_process"): is_java_process = get.is_java_process.strip() if is_java_process in ("0", 0, False, "false"): is_java_process = False else: is_java_process = True if hasattr(get, "search"): search = get.search.strip() res = [] rep_bt_tomcat = re.compile(r"(/usr/local/bttomcat/.*)|(/www/server/bt_tomcat_web/.*)/jsvc") rep_not_use = re.compile( r"php|system|crond|NetworkManager|uwsgi|dotnet|bash|/www/server/tamper|mysql|nginx|httpd|tail|python|sshd" ) if is_java_process: target_list = utils.jps() for pid in target_list: try: p = psutil.Process(pid) if search and not (search in p.name() or search in ' '.join(p.cmdline())): # 有搜索条件,但不符合搜索条件 continue if rep_bt_tomcat.search(p.exe()): continue res.append({ "pid": pid, "name": p.name(), "exe": p.exe(), "cmdline": p.cmdline(), "username": p.username(), "create_time:": p.create_time(), "status": p.status(), }) except: continue return res # 若未选择java进程, 则在所有进程中搜索 for i in psutil.process_iter(["pid", "name", "exe", "cmdline", "username", "create_time", "status"]): if not i.exe(): continue if rep_not_use.search(i.exe()): continue if search and not (search in i.name() or search in ' '.join(i.cmdline())): # 有搜索条件, 但不符合搜索条件 continue if rep_bt_tomcat.search(i.exe()): continue try: res.append({ "pid": i.pid, "name": i.name(), "exe": i.exe(), "cmdline": i.cmdline(), "username": i.username(), "create_time:": i.create_time(), "status": i.status(), }) except: continue return res @staticmethod def process_info_for_create(get): try: pid = int(get.pid.strip()) except: return json_response(status=False, msg="Parameter error") try: p = psutil.Process(pid) cmdline = p.cmdline() ports = [] for i in p.connections(): if i.status == "LISTEN" and i.laddr and i.laddr.port not in ports: ports.append(i.laddr.port) user = p.username() env = p.environ() exe = p.exe() except: public.print_log(public.get_error_info()) return json_response(status=False, msg="进程解析失败") pwd_path = env.get("PWD") env_list = [] for key, value in env.items(): if key.lower().find("spring") != -1 or key.lower().find("java") != -1: env_list.append({"k": key, "v": value}) java_bin = "" if exe.endswith("java"): # 目前支持用户使用java命令启动的java进程 java_bin = exe if cmdline[0].endswith("java"): cmdline[0] = java_bin jar_path = "" target_jar_idx = None for idx, i in enumerate(cmdline): if i.endswith(".jar") or i.endswith(".war") and not (i.startswith("-") or "=" in i): if not jar_path: jar_path = i target_jar_idx = idx # 处理获取的java路径 project_name = "" if jar_path: if not jar_path.startswith("/"): # 处理相对路径 jar_path = os.path.abspath(os.path.join(pwd_path, jar_path)) cmdline[target_jar_idx] = jar_path project_name = os.path.basename(jar_path).rsplit(".", 1)[0] if not os.path.exists(jar_path): jar_path = None return json_response(status=True, data={ "project_name": project_name, "jar_path": jar_path, "java_bin": java_bin, "port": ports[0] if len(ports) else 0, "user": user, "env": env_list, "cmdline": " ".join(cmdline), "pid": pid, }) @staticmethod def check_spring_boot_args(get) -> Union[Dict, str]: by_process = 0 domains = [] proxy_path = "/" jmx_status = False watch_file = False env_file = "" env_list = [] try: project_name = get.project_name.strip() project_jar = get.project_jar.strip() project_jdk = get.project_jdk.strip() # port = int(get.port) run_user = get.run_user.strip() project_cmd = get.project_cmd.strip() # type:str ps = get.project_ps.strip() if hasattr(get, "env_file"): env_file = get.env_file.strip() if not isinstance(env_file, str) and os.path.exists(env_file): return "环境变量文件不存在" if hasattr(get, "env_list"): env_list = get.env_list if not isinstance(env_list, list): return "环境变量格式错误" if hasattr(get, "domains"): domains = get.domains if not isinstance(domains, list): return "域名参数错误" if hasattr(get, "proxy_path"): proxy_path = get.proxy_path if not isinstance(domains, str) and not proxy_path.startswith("/"): return "代理路径必须是以/开头的字符串" if hasattr(get, "jmx_status"): jmx_status = utils.js_value_to_bool(get.jmx_status) if hasattr(get, "watch_file"): watch_file = utils.js_value_to_bool(get.watch_file) if hasattr(get, "by_process"): by_process = int(get.by_process) if by_process < 0: by_process = 0 except (AttributeError, ValueError): return "Parameter format error" if not project_name: return "The project name cannot be empty" if not 1 <= len(project_name) <= 20: return "项目名称不超过20字符" if public.M('sites').where('name=?', (project_name,)).count(): return '指定项目名称已存在: {}'.format(project_name) if not os.path.exists(project_jar): return '请输入正确的jar包路径' project_jdk = utils.normalize_jdk_path(project_jdk) if not isinstance(project_jdk, str): return json_response(False, '项目JDK路径不存在') if not os.path.exists(project_jdk): return '请输入正确的JDK路径' if not utils.test_jdk(project_jdk): return '请输入正确的JDK路径' if project_cmd.find(project_jdk) == -1: return '启动命令中不包含JDK路径,请确认无误再添加' if project_cmd.find(project_jar) == -1: return '启动命令中不包含jar路径,请确认无误后再添加' # if not by_process and not utils.check_port(port): # return '端口格式错误或已被其他进程使用' if domains: if not public.is_apache_nginx(): return "未安装Nginx" err_msg = public.checkWebConfig() if isinstance(err_msg, str): return ( 'WEB服务器配置配置文件错误ERROR:<br><font style="color:red;">' + err_msg.replace("\n", '<br>') + '</font>' ) if run_user not in [i["username"] for i in RealUser().get_user_list()["data"]]: return '请输入正确的启动用户' if domains: domains, err = normalize_domain(*domains) if err: return "<br>".join(["域名:{},错误信息:{}".format(i['domain'], i['msg']) for i in err]) else: for d, p in domains: if public.M('domain').where('name=?', d).count(): return '指定域名已存在: {}'.format(d) return { "project_name": project_name, "project_jar": project_jar, "project_jdk": project_jdk, # "port": port, "run_user": run_user, "project_cmd": project_cmd, "ps": ps, "env_list": env_list, "env_file": env_file, "domains": ["{}:{}".format(i[0], i[1]) for i in domains], "proxy_path": proxy_path, "jmx_status": jmx_status, "watch_file": watch_file, "by_process": by_process, } def create_spring_boot_project(self, get): config = self.check_spring_boot_args(get) if isinstance(config, str): return json_response(status=False, msg=config) project_config = { 'ssl_path': '/www/wwwroot/java_node_ssl', 'project_jdk': config["project_jdk"], 'project_name': config["project_name"], 'project_jar': config["project_jar"], 'bind_extranet': 0 if not config["domains"] else 1, 'domains': config["domains"], 'run_user': get.run_user.strip(), 'jmx_status': config["jmx_status"], 'project_cmd': config["project_cmd"], 'java_type': 'springboot', 'jar_path': os.path.dirname(config["project_jar"]), 'pids': "{}/pids/{}.pid".format(self._java_project_vhost, config["project_name"]), 'logs': "{}/{}.log".format(self._java_spring_boot_log_path, config["project_name"]), 'scripts': "{}/scripts/{}.sh".format(self._java_project_vhost, config["project_name"]), 'watch_file': config["watch_file"], 'env_list': config["env_list"], 'env_file': config["env_file"], 'proxy_path': config["proxy_path"], "nohup_log": True, "static_info": {}, "proxy_info": [], "daemon_status": False, "server_name_suffix": "" } pdata = { 'name': config["project_name"], 'path': config["project_jar"], 'ps': config["ps"], 'status': 1, 'type_id': 0, 'project_type': 'Java', 'project_config': json.dumps(project_config), 'addtime': public.getDate() } project_id = public.M('sites').insert(pdata) if not isinstance(project_id, int): return json_response(status=False, msg='创建项目失败') pdata["project_config"] = project_config pdata["id"] = project_id if project_config["domains"]: for domain in project_config["domains"]: domain_name, port = domain.split(":") public.M('domain').insert( { 'name': domain_name, 'pid': project_id, 'port': port, 'addtime': public.getDate() } ) error_msg = self._setup_spring_boot_project(pdata, by_process=config["by_process"]) if error_msg: return json_response(status=True, msg=error_msg) return json_response(status=True, msg='项目创建成功, 若未能启动成功, 请查看日志信息,获取启动失败原因') def _setup_spring_boot_project(self, pdata, by_process=False) -> Optional[str]: project_config = pdata["project_config"] if project_config["jmx_status"]: pass # project_config["project_cmd"] = self._build_jmx_cmd(project_config["project_cmd"], project_config['jmx_status']) if not by_process: start_status = self._start_spring_boot_project(pdata, write_systemd_file=True, need_wait=False) if isinstance(start_status, dict): start_status = start_status["msg"] else: public.writeFile(project_config['pids'], str(by_process)) start_status = "Successfully added" if project_config["watch_file"]: add_project_watch( p_name=project_config["project_name"], p_type="java", site_id=pdata["id"], watch_path=project_config["project_jar"] ) if project_config["domains"]: res = self.create_config( pdata, domains=[i.split(":", 1) for i in project_config["domains"]], use_ssl=False, ) return start_status # 实际启动项目的函数 def _start_spring_boot_project(self, project_data: dict, write_systemd_file=True, need_wait=True, ) -> dict: old_pid = self.get_project_pid(project_data) project_config = project_data["project_config"] server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "") # 先检查环境变量文件是否存在,没有的时候先写空 env_file = project_config['env_file'] env_list = project_config['env_list'] env_path = "{}/env/{}.env".format(self._java_project_vhost, project_config["project_name"]) if isinstance(env_list, list): if not os.path.exists(os.path.dirname(env_path)): os.makedirs(os.path.dirname(env_path), 0o755) public.writeFile(env_path, "\n".join( ["{}={}".format(i["k"], i["v"]) for i in env_list if "k" in i and "v" in i] )) else: if not os.path.isfile(env_path): public.writeFile(env_path, "") if env_file and not os.path.isfile(env_file): if not os.path.exists(os.path.dirname(env_file)): os.makedirs(os.path.dirname(env_file), 0o755) public.writeFile(env_file, "") log_file = project_config['logs'] pid_file = project_config['pids'] if not os.path.exists(log_file): public.writeFile(log_file, "") if not os.path.exists(pid_file): public.writeFile(pid_file, "0") # 修改文件权限 public.ExecShell( "chown {usr}:{usr} {file}".format(usr=project_config["run_user"], file=project_config["project_jar"]) ) public.ExecShell( "chown {usr}:{usr} {file}".format(usr=project_config["run_user"], file=log_file) ) public.ExecShell( "chown {usr}:{usr} {file}".format(usr=project_config["run_user"], file=pid_file) ) utils.pass_dir_for_user(os.path.dirname(log_file), project_config['run_user']) # 如果存在服务文件,没有要求写入时,就直接执行启动停止操作 s_admin = RealServer() if not write_systemd_file: res = s_admin.daemon_status(server_name) msg = res['msg'] if msg in ("运行中", "未运行"): s_admin.daemon_admin(server_name, "restart") if need_wait: return self._wait_start_status(project_data, old_pid=old_pid) else: return json_response(status=True, msg="操作已执行") if msg == "operation failure": return res # 还有一种服务文件丢失的情况走下面的写文件并启动 # 要求写入时, 重新写入启动文件 project_cmd = project_config['project_cmd'] # 前置准备 if project_config["nohup_log"]: collect_log = log_file else: collect_log = '/dev/null' jar_path = project_config['jar_path'] env = "EnvironmentFile={}".format(env_path) if env_file: env += "\nEnvironmentFile={}".format(env_file) res = s_admin.create_daemon( server_name=server_name, pid_file=pid_file, start_exec=project_cmd, workingdirectory=jar_path, user=project_config["run_user"], logs_file=collect_log, environments=env, restart_type="always" if project_config.get("daemon_status", False) else "no" ) if not res["status"]: return res s_admin.daemon_admin(server_name, "start") if need_wait: return self._wait_start_status(project_data, old_pid=old_pid) return json_response(status=True, msg="操作已执行") def _wait_start_status(self, project_data: dict, old_pid: int) -> dict: # 当为重启时,等待关闭 if old_pid: try: p = psutil.Process(old_pid) for i in range(20): time.sleep(0.05) if not p.is_running(): break except: pass project_config = project_data['project_config'] pid = self.get_project_pid(project_data) if not pid: for i in range(2): time.sleep(0.05) pid = self.get_project_pid(project_data) if pid: break if not pid: return json_response(False, msg="启动失败,详细信息请查看日志", data=public.GetNumLines(project_config["logs"], 30)) for i in range(3): port = self._get_port_by_pid(pid) if port: return json_response(True, "启动成功") time.sleep(0.05) if i > 1 and i % 5 == 0: if pid not in psutil.pids(): return json_response(False, msg="启动失败,详细信息请查看日志", data=public.GetNumLines(project_config["logs"], 30)) pid = self.get_project_pid(project_data) if not pid: return json_response(False, msg="启动失败,详细信息请查看日志", data=public.GetNumLines(project_config["logs"], 30)) else: return json_response(True, "未检查到端口监听,启动过程超时,请注意启动情况") @staticmethod def _get_port_by_pid(pid: int) -> Optional[int]: try: p = psutil.Process(pid) for i in p.connections(): if i.status == "LISTEN": return i.laddr.port except: return None # # 启动脚本 # start_cmd = '''#!/bin/bash # PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin # export PATH # {env} # cd {jar_path} # nohup {project_cmd} {collect_log} & # echo $! > {pid_file} # '''.format( # jar_path=jar_path, # project_cmd=project_cmd, # pid_file=pid_file, # log_file=log_file, # env=env, # collect_log=collect_log # ) # script_file = project_config['scripts'] # # 写入启动脚本 # public.writeFile(script_file, start_cmd) # if os.path.exists(pid_file): # os.remove(pid_file) # public.set_mode(script_file, 755) # # 修改文件权限 # public.ExecShell( # "chown {usr}:{usr} {file}".format(usr=project_config["run_user"], file=project_config["project_jar"]) # ) # if not os.path.exists(log_file): # public.writeFile(log_file, "") # # public.ExecShell( # "chown {usr}:{usr} {file}".format(usr=project_config["run_user"], file=log_file) # ) # utils.pass_dir_for_user(os.path.dirname(log_file), project_config['run_user']) # # 执行脚本文件 # res = public.ExecShell("bash {}".format(script_file), user=project_config['run_user'], env=os.environ.copy()) # # time.sleep(1) # error_msg = '启动失败,您可以尝试查看控制台日志,以获取具体失败原因' # if not os.path.exists(pid_file): # return error_msg # # # 获取PID # try: # pid = int(public.readFile(pid_file)) # except: # return error_msg # if pid not in psutil.pids(): # return error_msg # # return None @staticmethod def _build_jmx_cmd(cmd_str: str, jmx_status: bool): has_jmx_args = cmd_str.find("-Dcom.sun.management.jmxremote") != -1 if not jmx_status: if not has_jmx_args: return cmd_str cmd_str_list = cmd_str.split(" ") for i in range(len(cmd_str_list) - 1, -1, -1): if cmd_str_list[i].startswith("-Dcom.sun.management.jmxremote"): cmd_str_list.pop(i) if cmd_str_list[i].startswith("-Djava.rmi.server.hostname=127.0.0.1"): cmd_str_list.pop(i) return " ".join(cmd_str_list) if jmx_status and has_jmx_args: port = re.search(r"-Dcom\.sun\.management\.jmxremote\.port=(?P<port>\d+)", cmd_str) if not utils.check_port(port.group("port")): # 如果原来的port被占用了,则生成一个随机的port并替换 cmd_str = re.sub( r"-Dcom\.sun\.management\.jmxremote\.port=(\d+)", "-Dcom.sun.management.jmxremote.port={}".format(utils.create_a_not_used_port()), cmd_str ) return cmd_str add_cmd = ( " -Dcom.sun.management.jmxremote" " -Dcom.sun.management.jmxremote.port={}" " -Djava.rmi.server.hostname=127.0.0.1" " -Dcom.sun.management.jmxremote.local.only=true" " -Dcom.sun.management.jmxremote.authenticate=false" " -Dcom.sun.management.jmxremote.ssl=false" ).format(utils.create_a_not_used_port()) cmd_str = cmd_str.lstrip(" ") first_space_idx = cmd_str.find(" ") # 把jmx的配置放到第一个空格之后 if first_space_idx == -1: return cmd_str + add_cmd else: return cmd_str[:first_space_idx] + add_cmd + cmd_str[first_space_idx:] @staticmethod def check_tomcat_args(get) -> Union[Dict, str]: port = None jdk_path = None try: domain = get.domain.strip() tomcat_version = int(get.tomcat_version) project_path = get.project_path.strip() if hasattr(get, "port"): port = int(get.port) if hasattr(get, "jdk_path"): jdk_path = get.jdk_path.strip() ps = get.project_ps.strip() except: return "Parameter error" if not is_domain(domain): return "请输入正确的域名" if not os.path.exists(project_path): os.makedirs(project_path) public.set_own(project_path, 'www') if tomcat_version not in (7, 8, 9, 10): return "请选择正确的Tomcat版本" if jdk_path is not None: if not os.path.exists(jdk_path): return "JDK路径不存在" jdk_path = utils.normalize_jdk_path(jdk_path) if not isinstance(jdk_path, str): return '项目JDK路径不存在' if not utils.test_jdk(jdk_path): return "JDK路径错误" if port is not None: if not utils.check_port(port): return "端口被占用" domain_list, err = normalize_domain(domain) if not err: domain = domain_list[0] if public.M('domain').where('name=?', domain[0]).count(): return '指定域名已存在: {}'.format(domain[0]) project_name = domain[0] domain = "{}:{}".format(domain[0], domain[1]) else: return "<br>".join(["域名:{},错误信息:{}".format(i['domain'], i['msg']) for i in err]) return { "project_name": project_name, "project_jdk": jdk_path, "ps": ps, "port": port, "domains": [domain, ], "tomcat_version": tomcat_version, "project_path": project_path, } def create_tomcat_project(self, get): config = self.check_tomcat_args(get) if isinstance(config, str): return json_response(status=False, msg=config) tomcat = utils.bt_tomcat(config["tomcat_version"]) if not tomcat.installed: return json_response(status=False, msg="指定的Tomcat版本未安装") if config["project_jdk"] and tomcat.jdk_path != config["project_jdk"]: if not tomcat.replace_jdk(config["project_jdk"]): return json_response(status=False, msg="替换JDK失败") if config["port"] and not tomcat.set_port(config["port"]): return json_response(status=False, msg="设置端口失败") if not tomcat.add_host(config["project_name"], config["project_path"]): return json_response(status=False, msg="添加失败") # 有web服务且可以重启 if public.is_apache_nginx() and not isinstance(public.checkWebConfig(), str): bind_extranet = 1 else: bind_extranet = 0 if os.path.isfile(config["project_path"]): path = os.path.basename(config["project_path"]) else: path = config["project_path"] project_config = { 'project_name': config["project_name"], 'bind_extranet': bind_extranet, 'domains': config['domains'], 'tomcat_version': config["tomcat_version"], 'java_type': 'neizhi', 'server_xml': '/usr/local/bt_mod_tomcat/tomcat%s/conf/server.xml' % config["tomcat_version"], 'port': int(tomcat.port()), 'auth': '1', # 默认开机自动启动 'logs': os.path.dirname(tomcat.log_file), 'ssl_path': '/www/wwwroot/java_node_ssl', "proxy_info": [], } # 添加数据库信息 pdata = { 'name': config["project_name"], 'path': config["project_path"], 'ps': config["ps"], 'status': 1, 'type_id': 0, 'project_type': 'Java', 'project_config': json.dumps(project_config), 'addtime': public.getDate() } tomcat.save_config_xml() project_id = public.M('sites').insert(pdata) pdata["id"] = project_id for domain in config["domains"]: domain_name, port = domain.split(":") public.M('domain').insert({ 'name': domain_name, 'pid': project_id, 'port': port, 'addtime': public.getDate() }) tomcat.restart() pdata["project_config"] = project_config if bind_extranet: self.create_config( pdata, domains=[i.split(":") for i in config['domains']], use_ssl=False) return json_response(status=True, msg='项目创建成功') @staticmethod def check_site_tomcat_args(get) -> Union[Dict, str]: jdk_path = None try: domain = get.domain.strip() tomcat_version = int(get.tomcat_version) project_path = get.project_path.strip() if hasattr(get, "project_jdk"): jdk_path = get.project_jdk.strip() port = int(get.port) run_user = get.run_user.strip() ps = get.project_ps.strip() except: return "Parameter error" if not utils.check_port(port): return "端口已被使用" if not is_domain(domain): return "请输入正确的域名" if not os.path.exists(project_path): os.makedirs(project_path) public.set_own(project_path, 'www') if tomcat_version not in (7, 8, 9, 10): return "请选择正确的Tomcat版本" if jdk_path: if not os.path.exists(jdk_path): return "JDK路径不存在" jdk_path = utils.normalize_jdk_path(jdk_path) if not isinstance(jdk_path, str): return "JDK路径错误" if not utils.test_jdk(jdk_path): return "JDK检查错误" if run_user not in [i["username"] for i in RealUser().get_user_list()["data"]]: return '请输入正确的启动用户' domain_list, err = normalize_domain(domain) if err: return "<br>".join(["域名:{},错误信息:{}".format(i['domain'], i['msg']) for i in err]) else: for d, p in domain_list: if public.M('domain').where('name=?', d).count(): return '指定域名已存在: {}'.format(d) domain = domain_list[0] project_name = domain[0] domain = "{}:{}".format(domain[0], domain[1]) return { "project_name": project_name, "project_jdk": jdk_path, "run_user": run_user, "port": port, "ps": ps, "domains": [domain, ], "tomcat_version": tomcat_version, "project_path": project_path, 'ssl_path': '/www/wwwroot/java_node_ssl', } def create_site_tomcat_project(self, get): config = self.check_site_tomcat_args(get) if isinstance(config, str): return json_response(status=False, msg=config) site_tomcat_path = os.path.join(self._site_tomcat_path, config["project_name"]) if os.path.exists(site_tomcat_path): return json_response(status=False, msg="该网站已经存在。如想建立请删除%s" % site_tomcat_path) # 首先需要先复制好文件过去 if not os.path.exists(site_tomcat_path): os.makedirs(site_tomcat_path) bt_tomcat_back = "/usr/local/bttomcat/tomcat_bak%d" if not os.path.exists(bt_tomcat_back % config["tomcat_version"] + '/conf/server.xml'): return json_response(False, "tomcat7的配置文件不存在,请重新安装tomcat7") public.ExecShell('cp -r %s/* %s && chown -R %s:%s %s' % ( bt_tomcat_back % int(config["tomcat_version"]), site_tomcat_path, config["run_user"], config["run_user"], site_tomcat_path )) tomcat = utils.site_tomcat(config["project_name"]) if not tomcat: return json_response(status=False, msg="Tomcat未能初始化成功") # server.xml if os.path.exists(site_tomcat_path + '/conf/server.xml'): tomcat.reset_tomcat_server_config(config["port"]) else: os.system('rm -rf %s' % site_tomcat_path) return json_response(False, "配置文件不存在请重新安装tomcat后尝试新建网站") if tomcat.jdk_path != config["project_jdk"]: res = tomcat.replace_jdk(config["project_jdk"]) if res: os.system('rm -rf %s' % site_tomcat_path) return json_response(status=False, msg="JDK替换失败") log_path = "/www/wwwlogs/java/{}".format(config["project_name"]) if not os.path.exists(log_path) or os.path.isfile(log_path): os.makedirs(log_path, mode=0o755) tomcat.change_log_path(log_path, prefix=config["project_name"].replace(".", '_')) if not tomcat.add_host(config["project_name"], config["project_path"]): os.system('rm -rf %s' % site_tomcat_path) return json_response(status=False, msg="添加失败") # 有web服务且可以重启 if public.is_apache_nginx() and not isinstance(public.checkWebConfig(), str): bind_extranet = 1 else: bind_extranet = 0 if os.path.isfile(config["project_path"]): path = os.path.basename(config["project_path"]) else: path = config["project_path"] project_config = { 'project_name': config["project_name"], "project_jdk": config["project_jdk"], 'bind_extranet': bind_extranet, 'domains': config["domains"], 'tomcat_version': config["tomcat_version"], 'java_type': 'duli', 'server_xml': site_tomcat_path + "/conf/server.xml", 'port': config["port"], "run_user": config["run_user"], 'logs': log_path, "proxy_info": [], } pdata = { 'name': config["project_name"], 'path': config["project_path"], 'ps': config["ps"], 'status': 1, 'type_id': 0, 'project_type': 'Java', 'project_config': json.dumps(project_config), 'addtime': public.getDate() } tomcat.save_config_xml() project_id = public.M('sites').insert(pdata) pdata["id"] = project_id for domain in config["domains"]: domain_name, port = domain.split(":") public.M('domain').insert({ 'name': domain_name, 'pid': project_id, 'port': port, 'addtime': public.getDate() }) tomcat.restart(by_user=config["run_user"]) pdata["project_config"] = project_config if bind_extranet: self.create_config( pdata, domains=[i.split(":") for i in config['domains']], use_ssl=False) return json_response(status=True, msg='项目创建成功') def create_project(self, get): try: project_type = int(get.project_type) except: return json_response(status=False, msg="项目类型错误") if project_type == 0: return self.create_spring_boot_project(get) elif project_type == 1: return self.create_tomcat_project(get) else: return self.create_site_tomcat_project(get) @staticmethod def get_project_find(project_name: str) -> Optional[dict]: project_info = public.M('sites').where('project_type=? AND name=?', ('Java', project_name)).find() if not project_info: return None # 做旧项目的兼容性处理 project_info['project_config'] = json.loads(project_info['project_config']) if "jmx_status" not in project_info['project_config']: project_info['project_config']['jmx_status'] = False if "nohup_log" not in project_info['project_config']: project_info['project_config']['nohup_log'] = True if "env_file" not in project_info['project_config']: project_info['project_config']['env_file'] = '' if "env_list" not in project_info['project_config']: project_info['project_config']['env_list'] = [] if "static_path" in project_info['project_config'] and "static_info" not in project_info['project_config']: project_info['project_config']['static_info'] = { "path": project_info['project_config']['static_path'], "status": True, "index": "", "use_try_file": True } public.M('sites').where("id=?", (project_info['id'],)).update( {'project_config': json.dumps(project_info['project_config'])} ) if "proxy_info" not in project_info['project_config']: rsp = RealServerProxy(project_info) proxy_list = rsp.get_proxy_list() project_info['project_config']['proxy_info'] = proxy_list if 'auth' in project_info['project_config'] and project_info['project_config']['auth'] in (1, "1") and \ "daemon_status" not in project_info['project_config']: project_info['project_config']['daemon_status'] = True if 'daemon_status' not in project_info['project_config']: project_info['project_config']['daemon_status'] = False return project_info def modify_spring_boot_project(self, get, project_data: Optional[dict] = None): if not project_data: try: project_name = self.get_project_find(get.project_name.strip()) except: return json_response(status=False, msg="项目名称错误") if not project_data: return json_response(status=False, msg="The project does not exist") else: project_name = project_data['name'] change_flag = False project_config = project_data['project_config'] if hasattr(get, 'run_user') and get.run_user.strip() != project_config['run_user']: project_config['run_user'] = get.run_user.strip() change_flag = True if hasattr(get, 'project_jdk'): input_jdk = utils.normalize_jdk_path(get.project_jdk.strip()) if not isinstance(input_jdk, str): return json_response(False, 'JDK检测错误') if input_jdk != project_config['project_jdk']: project_config['project_jdk'] = input_jdk change_flag = True if hasattr(get, 'project_jar') and get.project_jar.strip() != project_config['project_jar']: project_config['project_jar'] = get.project_jar.strip() if not os.path.isfile(project_config['project_jar']): return json_response(False, '项目jar包不存在') project_config['jar_path'] = os.path.dirname(project_config['project_jar']) change_flag = True if hasattr(get, 'project_cmd') and get.project_cmd.strip(): if get.project_cmd.strip() != project_config['project_cmd']: project_config['project_cmd'] = get.project_cmd.strip() change_flag = True else: return json_response(False, '缺少project_cmd参数') if hasattr(get, 'daemon_status'): daemon_status = utils.js_value_to_bool(get.daemon_status) if daemon_status != project_config['daemon_status']: project_config['daemon_status'] = daemon_status change_flag = True # 检查jar包是否在cmd中 if project_config['project_cmd'].find(get.project_jar.strip()) == -1: return json_response(False, '项目jar包名称不在项目启动命令中,请检查') if hasattr(get, 'jmx_status') and utils.js_value_to_bool(get.jmx_status) != project_config['jmx_status']: project_config['jmx_status'] = utils.js_value_to_bool(get.jmx_status) change_flag = True if hasattr(get, "env_file") and get.env_file.strip() != project_config['env_file']: project_config['env_file'] = get.env_file.strip() if project_config['env_file'] and not os.path.exists(project_config['env_file']): return json_response(False, '项目环境文件不存在') change_flag = True if hasattr(get, "env_list"): env_list = get.env_list if isinstance(env_list, str): try: env_list = json.loads(env_list) except: return json_response(False, '项目环境变量格式错误') if not isinstance(env_list, list): return json_response(False, '项目环境变量格式错误') if env_list != project_config['env_list']: project_config['env_list'] = env_list change_flag = True if hasattr(get, 'watch_file'): project_config['watch_file'] = utils.js_value_to_bool(get.watch_file) if project_config['watch_file']: add_project_watch(p_name=get.project_name.strip(), p_type="java", site_id=project_data["id"], watch_path=get.project_jar.strip()) else: del_project_watch(get.project_name.strip()) if change_flag: project_config["change_flag"] = True pdata = { 'name': project_name, 'path': get.project_jar.strip(), 'ps': get.project_ps.strip(), 'project_config': json.dumps(project_config) } public.M('sites').where('name=?', (get.project_name,)).update(pdata) return json_response(True, '项目修改成功,重启后生效') def modify_tomcat_project(self, get, project_data: Optional[dict] = None): if not project_data: try: project_name = self.get_project_find(get.project_name.strip()) except: return json_response(status=False, msg="项目名称错误") if not project_data: return json_response(status=False, msg="The project does not exist") else: project_name = project_data['name'] project_config = project_data['project_config'] tomcat = utils.bt_tomcat(project_config["tomcat_version"]) flag = False # 更换JDK if hasattr(get, 'project_jdk') and get.project_jdk: jdk_path = utils.normalize_jdk_path(get.project_jdk.strip()) if not isinstance(jdk_path, str): return json_response(False, 'JDK检测错误') if jdk_path != tomcat.jdk_path: if not utils.test_jdk(jdk_path): return json_response(False, '当前JDK不可用') res = tomcat.replace_jdk(jdk_path) if not res: return json_response(False, res) flag = True if hasattr(get, 'project_path'): if get.project_path.strip() == project_data['path']: pass else: if not tomcat.set_host_path_by_name(project_name, get.project_path.strip()): return json_response(False, '项目路径设置失败') project_data['path'] = get.project_path.strip() # 更换描述 if hasattr(get, 'project_ps'): if get.project_ps.strip() != project_data['ps']: project_data['ps'] = get.project_ps.strip() if flag: tomcat.restart() pdata = { 'path': project_data['path'], 'ps': project_data['ps'], } public.M('sites').where('name=?', (get.project_name,)).update(pdata) return json_response(True, '项目修改成功') def modify_site_tomcat_project(self, get, project_data: Optional[dict] = None): if not project_data: try: project_name = self.get_project_find(get.project_name.strip()) except: return json_response(status=False, msg="项目名称错误") if not project_data: return json_response(status=False, msg="The project does not exist") else: project_name = project_data['name'] project_config = project_data['project_config'] tomcat = utils.site_tomcat(project_name) if not tomcat: return json_response(False, '项目的Tomcat已被删除,请尝试修复项目') flag = False # 更换JDK if hasattr(get, 'project_jdk') and get.project_jdk: jdk_path = utils.normalize_jdk_path(get.project_jdk.strip()) if not isinstance(jdk_path, str): return json_response(False, 'JDK检测错误') if jdk_path != tomcat.jdk_path: if not utils.test_jdk(jdk_path): return json_response(False, '当前JDK不可用') res = tomcat.replace_jdk(jdk_path) if isinstance(res, str): return json_response(False, res) flag = True project_config["project_jdk"] = jdk_path if hasattr(get, 'port'): try: port = int(get.port) except: return json_response(False, '端口信息错误') if port != tomcat.port(): if not utils.check_port(port): return json_response(False, '端口已被占用') res = tomcat.set_port(port) if not res: return json_response(False, '端口设置失败') tomcat.save_config_xml() flag = True project_config["port"] = port # 更换描述 if hasattr(get, 'project_ps'): if get.project_ps.strip() != project_data['ps']: project_data['ps'] = get.project_ps.strip() if hasattr(get, 'project_path'): if get.project_path.strip() != project_data['path']: if not tomcat.set_host_path_by_name(project_name, get.project_path.strip()): return json_response(False, '项目路径设置失败') project_data['path'] = get.project_path.strip() flag = True if hasattr(get, 'run_user'): if "run_user" not in project_config: project_config["run_user"] = "root" if get.run_user.strip() != project_config['run_user']: run_user = get.run_user.strip() if run_user not in [i["username"] for i in RealUser().get_user_list()["data"]]: return json_response(False, '请输入正确的启动用户') else: project_config["run_user"] = run_user flag = True if flag: tomcat.restart(by_user=project_config["run_user"]) pdata = { 'path': project_data['path'], 'ps': project_data['ps'], 'project_config': json.dumps(project_config), } public.M('sites').where('name=?', (get.project_name,)).update(pdata) return json_response(True, '项目修改成功') def modify_project(self, get): try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(status=False, msg="The project does not exist") project_config = project_data["project_config"] if project_config["java_type"] == "springboot": return self.modify_spring_boot_project(get, project_data) elif project_config["java_type"] == "duli": return self.modify_site_tomcat_project(get, project_data) else: return self.modify_tomcat_project(get, project_data) def get_project_pid(self, project_data: dict) -> Optional[int]: # 从pid文件中获取项目pid project_config = project_data["project_config"] if project_config["java_type"] == "springboot": pid_file = project_config["pids"] pid = None if os.path.isfile(pid_file): try: pid = int(public.readFile(pid_file)) except: pass elif project_config["java_type"] == "neizhi": pid = utils.bt_tomcat(project_config["tomcat_version"]).pid() else: pid = utils.site_tomcat(project_data["name"]).pid() if not pid and project_config["java_type"] == "springboot": try: return self._get_pid_by_command(project_data) except: return None try: psutil.Process(pid) except: return None return pid @staticmethod def _get_pid_by_command(project_data: dict) -> Optional[int]: project_config = project_data["project_config"] server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "") print(server_name) server_admin = RealServer() pid = server_admin.get_daemon_pid(server_name)["data"] if pid == 0: time.sleep(0.5) pid = server_admin.get_daemon_pid(server_name)["data"] if isinstance(pid, int): try: p = psutil.Process(pid) if p.is_running(): public.writeFile(project_data["project_config"]['pids'], str(pid)) return pid except: pass if project_config["java_type"] == "springboot": jdk_path = utils.normalize_jdk_path(project_config['project_jdk']) project_jar = project_config['project_jar'] jar_name = os.path.basename(project_jar) jar_cmd = project_config['project_cmd'] port_rep = re.search(r"--server\.port=\d+", jar_cmd) pids = [] for pro in psutil.process_iter(['pid', 'exe', 'cmdline']): if pro.status() == "zombie": continue try: if port_rep and port_rep.group() not in pro.cmdline(): continue if jdk_path == utils.normalize_jdk_path(pro.exe()) and any((jar_name in i for i in pro.cmdline())): pids.append(pro.pid) except: pass if not pids: return None running_pid = [] for pid in pids: if pid in psutil.pids(): running_pid.append(pid) if len(running_pid) == 1: public.writeFile(project_data["project_config"]['pids'], str(running_pid[0])) return running_pid[0] for pid in running_pid: p = psutil.Process(pid) if p.ppid() not in running_pid: public.writeFile(project_data["project_config"]['pids'], str(pid)) return pid return None def project_process(self, project_data) -> Optional[psutil.Process]: pid = self.get_project_pid(project_data) if not pid: return None try: return psutil.Process(pid) except: return None def start_spring_boot_project(self, project_data: dict, wait: bool = True): change_flag = False project_config = project_data['project_config'] if "change_flag" in project_config: change_flag = project_config.get("change_flag", False) del project_config["change_flag"] public.M("sites").where("id=?", (project_data["id"],)).update( {"project_config": json.dumps(project_config)} ) res = self._start_spring_boot_project(project_data, change_flag, need_wait=wait) if res["status"] is True: utils.start_by_user(project_data["id"]) return res def start_project(self, get): try: project_data = self.get_project_find(get.project_name) except: return json_response(False, '项目名称参数错误') if not project_data: return json_response(False, 'The project does not exist') p = self.project_process(project_data) if p and p.is_running(): return json_response(False, '项目已启动') project_config = project_data['project_config'] if project_config["java_type"] == "springboot": return self.start_spring_boot_project(project_data) elif project_config["java_type"] == "neizhi": res = utils.bt_tomcat(project_config["tomcat_version"]).start() if not res: return json_response(False, '项目启动失败') else: tomcat = utils.site_tomcat(project_config["project_name"]) if not tomcat: return json_response(False, '独立项目的Tomcat文件丢失,请尝试修复项目') if not tomcat.running(): res = tomcat.start() if not res: return json_response(False, '项目启动失败') utils.start_by_user(project_data["id"]) return json_response(True, "项目启动成功") def stop_project(self, get): try: project_data = self.get_project_find(get.project_name) except: return json_response(False, '项目名称参数错误') if not project_data: return json_response(False, 'The project does not exist') project_config = project_data['project_config'] if project_config["java_type"] == "springboot": server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "") s_admin = RealServer() if s_admin.daemon_status(server_name)["msg"] == "服务不存在!": self.stop_by_kill_pid(project_data) if os.path.isfile(project_config["pids"]): os.remove(project_config["pids"]) else: s_admin.daemon_admin(server_name, "stop") utils.stop_by_user(project_data["id"]) return json_response(True, msg="项目停止指令已执行") elif project_config["java_type"] == "neizhi": res = utils.bt_tomcat(project_config["tomcat_version"]).stop() if not res: return json_response(False, '项目停止失败') else: tomcat = utils.site_tomcat(project_config["project_name"]) if not tomcat: return json_response(False, '独立项目的Tomcat文件丢失,请尝试修复项目') if tomcat.running(): res = tomcat.stop() if not res: return json_response(False, '项目停止失败') utils.stop_by_user(project_data["id"]) return json_response(True, "项目停止成功") def stop_by_kill_pid(self, project_data): pid = self.get_project_pid(project_data) if not pid: return try: p = psutil.Process(pid) p.kill() except: pass def restart_project(self, get): try: project_data = self.get_project_find(get.project_name) except: return json_response(False, '项目名称参数错误') if not project_data: return json_response(False, 'The project does not exist') project_config = project_data['project_config'] if project_config["java_type"] == "springboot": s_admin = RealServer() server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "") if s_admin.daemon_status(server_name)["msg"] == "服务不存在!": self.stop_by_kill_pid(project_data) if os.path.isfile(project_config["pids"]): os.remove(project_config["pids"]) return self._start_spring_boot_project(project_data, write_systemd_file=True) if "change_flag" in project_config and project_config.get("change_flag", False): del project_config["change_flag"] s_admin.daemon_admin(server_name, "stop") s_admin.del_daemon(server_name) self.stop_by_kill_pid(project_data) if os.path.isfile(project_config["pids"]): os.remove(project_config["pids"]) public.M("sites").where("id=?", (project_data["id"],)).update( {"project_config": json.dumps(project_config)} ) return self._start_spring_boot_project(project_data, write_systemd_file=True) else: return self._start_spring_boot_project(project_data, write_systemd_file=False) self.stop_project(get) time.sleep(0.5) self.start_project(get) return json_response(True, "项目重启已执行") def project_list(self, get): """取项目列表""" p = 1 limit = 12 callback = "" order = "id desc" search = "" type_id = None try: if hasattr(get, "p"): p = int(get.p) if hasattr(get, "limit"): limit = int(get.limit) if hasattr(get, "callback"): callback = get.callback.strip() if hasattr(get, "order"): order = get.order.strip() if hasattr(get, "search"): search = get.search.strip() if hasattr(get, "type_id") and get.type_id: type_id = int(get.type_id) except: return json_response(False, '参数错误') type_filter = '' if type_id is not None: type_filter = ' AND type_id=?' if search: search = "%{}%".format(search) if type_filter: where_str = 'project_type=? AND (name LIKE ? OR ps LIKE ?)' + type_filter where_args = ('Java', search, search, type_id) else: where_str = 'project_type=? AND (name LIKE ? OR ps LIKE ?)' where_args = ('Java', search, search) count = public.M('sites').where(where_str, where_args).count() data = public.get_page(count, p, limit, callback) data['data'] = public.M('sites').where(where_str, where_args).limit( data['shift'] + ',' + data['row']).order(order).select() else: if type_filter: where_str = 'project_type=?' + type_filter where_args = ('Java', type_id) else: where_str = 'project_type=?' where_args = ('Java',) count = public.M('sites').where(where_str, where_args).count() data = public.get_page(count, p, limit, callback) data['data'] = public.M('sites').where(where_str, where_args).limit( data['shift'] + ',' + data['row']).order(order).select() for project_data in data['data']: project_config = json.loads(project_data['project_config']) project_data['project_config'] = project_config # 如果内置项目 或 独立项目 的tomcat配置文件丢失 if project_config['java_type'] == 'neizhi' or project_config['java_type'] == 'duli': if not os.path.exists(project_config['server_xml']): project_data['server_file_status'] = False else: project_data['server_file_status'] = True for i in range(len(data['data'])): self.get_project_stat(data['data'][i]) return data def get_project_stat(self, project_data: dict) -> dict: if isinstance(project_data['project_config'], str): project_config = json.loads(project_data['project_config']) project_data['project_config'] = project_config project_data["pid"] = self.get_project_pid(project_data) if project_data["project_config"]["java_type"] == "springboot": project_data["project_config"]["watch_file"] = use_project_watch(project_data["name"]) project_data["listen"] = [] project_data["ssl"] = RealSSLManger("java_").get_site_ssl_info(project_data["name"]) if not project_data["ssl"]: project_data["ssl"] = -1 if project_data["pid"]: project_data["pid_info"] = self.real_process.get_process_info_by_pid(project_data["pid"])["data"] listen = [] if project_data["pid_info"] and "connections" in project_data["pid_info"]: for connection in project_data["pid_info"]["connections"]: if connection["status"] == "LISTEN": listen.append(connection["local_port"]) project_data["listen"] = listen if project_data['project_config']["java_type"] == "springboot": project_data['project_config']["port"] = ",".join([str(i) for i in listen]) else: project_data["pid_info"] = None project_data["starting"] = False if project_data["pid"] and not project_data["listen"]: project_data["starting"] = True if os.path.exists("{}/nginx/{}.conf".format(self._vhost_path, project_data["name"])) or \ os.path.exists("{}/apache/{}.conf".format(self._vhost_path, project_data["name"])): project_data["bind_extranet"] = True else: project_data["bind_extranet"] = False if project_data['project_config']["java_type"] == "duli" and "project_jdk" not in project_data['project_config']: tomcat = utils.site_tomcat(project_data["name"]) if tomcat: project_data['project_config']["project_jdk"] = tomcat.jdk_path else: project_data['project_config']["project_jdk"] = "/usr/local/btjdk/jdk8" return project_data @staticmethod def _project_domain_list(project_id: int): return public.M('domain').where('pid=?', (project_id,)).select() def project_domain_list(self, get): try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist') data = self._project_domain_list(project_data['id']) return json_response(True, data=data) def add_domains(self, get): """ 为指定项目添加域名 """ try: if isinstance(get.domains, str): domains = json.loads(get.domains) else: domains = get.domains project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not isinstance(domains, list): return json_response(False, '域名参数错误') if not project_data: return json_response(False, 'The specified item does not exist') project_id = project_data['id'] project_name = project_data["name"] domain_list, err = normalize_domain(*domains) if err: return "<br>".join(["域名:{},错误信息:{}".format(i['domain'], i['msg']) for i in err]) res_domains = [] for d, p in domain_list: if not public.M('domain').where('name=?', (d,)).count(): public.M('domain').add('name,pid,port,addtime', (d, project_id, p, public.getDate())) self.write_project_log('成功添加域名{}到项目{}'.format(d, get.project_name)) res_domains.append({"name": d, "status": True, "msg": '添加成功'}) else: self.write_project_log('添加域名错误,域名{}已存在'.format(d)) res_domains.append({"name": d, "status": False, "msg": '添加失败,域名{}已存在'.format(d)}) all_domain = self._project_domain_list(project_id) print(all_domain) # 写配置文件 if utils.js_value_to_bool(project_data["project_config"]["bind_extranet"]): res = self._set_domain(project_data, [(i["name"], str(i["port"])) for i in all_domain]) if res: return json_response(True, msg="域名记录成功,但配置文件写入时失败:" + res, data=res_domains) return json_response(True, msg="添加成功", data=res_domains) def remove_domains(self, get): """ 移除指定项目中的域名 """ try: if isinstance(get.domains, str): remove_list = json.loads(get.domains) else: remove_list = get.domains project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist') if not isinstance(remove_list, list): return json_response(False, '域名参数错误') all_domain = self._project_domain_list(project_data["id"]) if not all_domain: return json_response(False, '指定项目中没有域名可被删除') bind_extranet = False if os.path.exists("{}/nginx/{}.conf".format(self._vhost_path, project_data["name"])) or \ os.path.exists("{}/apache/{}.conf".format(self._vhost_path, project_data["name"])): bind_extranet = True if len(all_domain) == 1 and bind_extranet: return json_response(False, '请至少保留一个域名,如无需外网映射,关闭即可', data=[{ "domain": all_domain[0]["name"], "status": False, "msg": "无法删除最后一个域名" }]) all_domain.sort(key=lambda x: x["id"], reverse=True) all_domain_id_dict = {i["id"]: i for i in all_domain} del_id_list = [i for i in all_domain_id_dict if i in remove_list] res_data = [] # 说明选中了所有域名,这时需要保持一个默认域名 default_domain = None if len(all_domain_id_dict) == len(del_id_list) and bind_extranet: default_domain = all_domain[0] del_id_list.remove(default_domain["id"]) for i in del_id_list: public.M('domain').delete(id=i) res_data.append( { "domain": all_domain_id_dict[i]["name"], "status": True, "msg": "删除成功" } ) self.write_project_log('成功删除域名{}'.format([all_domain_id_dict[i]["name"] for i in del_id_list])) if default_domain: res_data.append( { "domain": default_domain["name"], "status": False, "msg": "无法删除最后一个域名" } ) if bind_extranet: now_domain = self._project_domain_list(project_data["id"]) # 写配置文件 res = self._set_domain(project_data, [(i["name"], str(i["port"])) for i in now_domain]) if res: return json_response(False, msg="域名记录删除成功,但配置文件写入时失败:" + res, data=res_data) return json_response(True, msg="Successfully delete", data=res_data) def bind_extranet(self, get): """开放外网映射""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) if not public.is_apache_nginx(): return json_response(False, "未安装Nginx") err_msg = public.checkWebConfig() if isinstance(err_msg, str): msg = 'WEB服务器配置配置文件错误ERROR:<br><font style="color:red;">' + \ err_msg.replace("\n", '<br>') + '</font>' return json_response(False, msg=msg) res = self._open_config_file(project_data) if isinstance(res, str): return json_response(False, msg=res) project_config = project_data["project_config"] project_config["bind_extranet"] = 1 public.M('sites').where('id=?', (project_data["id"],)).update( {"project_config": json.dumps(project_config)} ) return json_response(True, msg="Successfully set") def unbind_extranet(self, get): """关闭外网映射""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_config = project_data["project_config"] self._close_apache_config_file(project_data) project_config["bind_extranet"] = 0 public.M('sites').where('id=?', (project_data["id"],)).update( {"project_config": json.dumps(project_config)} ) return json_response(True, msg="Successfully set") def remove_project(self, get): """删除指定项目""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_config = project_data["project_config"] project_name = project_data["name"] if project_config['java_type'] == 'duli': tomcat = utils.site_tomcat(project_name) # 关闭独立项目 if tomcat: tomcat.stop() if os.path.exists(tomcat.path): shutil.rmtree(tomcat.path) elif project_config['java_type'] == 'neizhi': # 删除tomcat站点 tomcat = utils.bt_tomcat(project_config["tomcat_version"]) tomcat.remove_host(project_name) tomcat.save_config_xml() if tomcat.running(): tomcat.restart() elif project_config['java_type'] == 'springboot': # 停止项目 server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "") s_admin = RealServer() s_admin.daemon_admin(server_name, "stop") s_admin.del_daemon(server_name) pid_file = project_config['pids'] if os.path.exists(pid_file): os.remove(pid_file) script_file = project_config['scripts'] if os.path.exists(script_file): os.remove(script_file) env_path = "{}/env/{}.env".format(self._java_project_vhost, project_config["project_name"]) if os.path.exists(env_path): os.remove(env_path) log_file = project_config['logs'] if os.path.exists(log_file): os.remove(log_file) else: return json_response(False, '项目类型错误') threading.Thread(target=remove_sites_service_config, args=(project_name, "java_")).start() public.M('domain').where('pid=?', (project_data['id'],)).delete() public.M('sites').where('name=?', (project_name,)).delete() self.write_project_log('删除Java项目{}'.format(get.project_name)) return json_response(True, '删除项目成功') def config_file_list(self, get): """获取配置文件列表""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_name = project_data["name"] res_list = [] bind_extranet = int(project_data["project_config"]["bind_extranet"]) != 0 if bind_extranet: if public.get_webserver() == "nginx": config_file = "{}/nginx/java_{}.conf".format(self._vhost_path, project_name) res_list.append( { "name": "nginx配置文件", "path": config_file, "status": os.path.exists(config_file), "type": "server" } ) else: config_file = "{}/apache/java_{}.conf".format(self._vhost_path, project_name) res_list.append( { "name": "apache配置文件", "path": config_file, "status": os.path.exists(config_file), "type": "server" } ) rewrite_file = "{}/rewrite/java_{}.conf".format(self._vhost_path, project_name) res_list.append( { "name": "伪静态配置文件", "path": rewrite_file, "status": os.path.exists(rewrite_file), "type": "rewrite" } ) p_list = RealProxy("java_").get_proxy_list(public.to_dict_obj({"sitename": project_name})) f, r_list = RealRedirect("java_").get_redirect_list(public.to_dict_obj({"sitename": project_name})) for p in p_list: res_list.append({ "name": "反向代理【{}】".format(p["proxyname"]), "path": p["proxy_conf_file"], "status": os.path.exists(p["proxy_conf_file"]), "type": "proxy" }) if f: for r in r_list: res_list.append({ "name": "重定向", "path": r["redirect_conf_file"], "status": os.path.exists(r["redirect_conf_file"]), "type": "redirect" }) if project_data["project_config"]["java_type"] == "neizhi": tomcat = utils.bt_tomcat(project_data["project_config"]["tomcat_version"]) res_list.append({ "name": "Tomcat【{}】配置文件".format(project_data["project_config"]["tomcat_version"]), "path": os.path.join(tomcat.path, "conf/server.xml"), "status": tomcat.installed, "type": "tomcat" }) elif project_data["project_config"]["java_type"] == "duli": tomcat = utils.site_tomcat(project_data["name"]) res_list.append({ "name": "Tomcat配置文件", "path": os.path.join(tomcat.path, "conf/server.xml"), "status": tomcat.installed, "type": "tomcat" }) else: t = time.time() pid = self.get_project_pid(project_data) if not pid: pid = 0 spc = SpringConfigParser( jar_path=project_data["project_config"]["project_jar"], process=pid, ) used, _ = spc.app_config() for i, _ in used: if i == "命令行或环境变量": continue profile = os.path.basename(i)[len(spc.config_name):] # 取出 - + profile + 后缀部分 if profile in (".yml", ".yaml", ".properties"): profile = "" else: profile = profile.rsplit(".", 1)[0] res_list.append({ "name": "Spring配置" + profile, "path": i, "status": True, "type": "local_spring" if i.startswith("/") else "spring", "data": spc.raw_data.get(i, "") }) sort_tuple = { "local_spring": 10, "spring": 9, "tomcat": 8, "server": 7, "proxy": 6, "redirect": 5, "rewrite": 4, } res_list.sort(key=lambda x: sort_tuple[x["type"]], reverse=True) return json_response(True, data=res_list) # 未使用 def project_log_list(self, get): """获取日志文件列表""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_name = project_data["name"] res = RealLogMgr(conf_prefix="java_").get_site_log_path(public.to_dict_obj({"sitename": project_name})) res_list = [] if isinstance(res, str): res_list.extend([ {"type": "access", "path": None, "log_size": 0, "msg": "无法从配置文件中获取日志文件路径"}, {"type": "error", "path": None, "log_size": 0, "msg": "无法从配置文件中获取错误日志文件路径"} ]) else: access_file = res["log_file"] error_file = res["error_log_file"] access_file_size = error_file_size = 0 if os.path.isfile(access_file): access_file_size = os.path.getsize(access_file) if os.path.isfile(error_file): error_file_size = os.path.getsize(error_file) res_list.extend([ {"type": "access", "path": access_file, "log_size": access_file_size, "msg": ""}, {"type": "error", "path": error_file, "log_size": error_file_size, "msg": ""} ]) project_config = project_data["project_config"] if project_config["java_type"] == "springboot": log_file = project_config['logs'] if not os.path.isfile(log_file): pass def get_command(self, get): """获取命令, 包含设置和取消jmx的设置""" project_cmd = None jmx_status = None try: if hasattr(get, "project_cmd"): project_cmd = get.project_cmd.strip() if hasattr(get, "jmx_status"): jmx_status = utils.js_value_to_bool(get.jmx_status) project_jdk = utils.normalize_jdk_path(get.project_jdk.strip()) project_jar = get.project_jar.strip() except json.JSONDecodeError: return json_response(False, '参数错误') if not isinstance(project_jdk, str): return json_response(False, '项目JDK路径不存在') project_jdk = os.path.join(project_jdk, "bin/java") if not os.path.isfile(project_jdk): return json_response(False, '项目JDK不存在') if not os.path.isfile(project_jar): return json_response(False, '项目jar不存在') if not isinstance(project_cmd, str) and project_cmd: cmd = '{} -jar {} -Xmx1024M -Xms256M'.format(project_jdk, project_jar) cmd = self._build_jmx_cmd(cmd, jmx_status) else: cmd = self._build_jmx_cmd(project_cmd, jmx_status) return json_response(True, data=cmd) def set_project_log_status(self, get): """设置项目日志是否开启""" try: project_data = self.get_project_find(get.project_name.strip()) status = utils.js_value_to_bool(get.status) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) if project_data["project_config"]["java_type"] == "springboot": project_config = project_data["project_config"] project_config["nohup_log"] = status project_config["change_flag"] = True pdata = { 'project_config': json.dumps(project_config) } public.M('sites').where('id=?', (project_data["id"],)).update(pdata) return json_response(True, "修改成功, 重启项目后生效") else: return json_response(False, "非springboot项目无法关闭") def get_jmx_status(self, get): """设置项目日志是否开启""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_config = project_data["project_config"] if not project_config["java_type"] == "springboot": return json_response(False, "目前支持springboot 项目的jmx 监控") pid = self.get_project_pid(project_data) if not pid: return json_response(False, "未启动的项目,不能获取jmx信息") jmx_info = self.get_jmx_data_by_pid(pid) if not jmx_info: return json_response(False, "项目未启用jmx,无法获取jmx信息") jmx_url = 'service:jmx:rmi:///jndi/rmi://{}:{}/jmxrmi'.format(jmx_info["host"], jmx_info["port"]) from mod.project.java.jmxquery import JMXConnection, JMXQuery try: # 创建 JMXConnection # JMX 连接信息 jmxConnection = JMXConnection( connection_uri=jmx_url, java_path=os.path.join(project_config["project_jdk"], "bin/java") ) jmxQuery = [JMXQuery("*:*")] # 执行查询 metrics = jmxConnection.query(jmxQuery) except Exception: public.print_log(public.get_error_info()) return json_response(False, "连接失败! {}".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(r"type=([\w\s]+)", metric.mBeanName) if not java_type_obj: continue java_type = java_type_obj.group(1) name_obj = re.search(r"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: Union[Dict[str, Any], List[Dict[str, Any]]] = 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 = "无限制" elif metric.attributeKey in size_list: value = public.to_size(value) elif metric.attributeKey in microsecond_list: value = datetime.fromtimestamp(int(value) / 1000).strftime('%Y-%m-%d %H:%M:%S') elif metric.attributeKey in nanoseconds_list: value = "{} 秒".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.fromtimestamp(int(value) / 1000).strftime('%Y-%m-%d %H:%M:%S') elif metric.attribute in nanoseconds_list: value = "{} 秒".format(int(value) / 1e9) type_info[metric.attribute] = value return json_response(True, data=jmx_status_info) @staticmethod def get_jmx_data_by_pid(pid) -> Optional[dict]: try: p = psutil.Process(pid) cmd_line = p.cmdline() except: return None data = { "port": "", "host": "127.0.0.1" } for i in cmd_line: if i.startswith("-Dcom.sun.management.jmxremote.port"): data["port"] = i.split("=")[1] if i.startswith("-Djava.rmi.server.hostname"): data["host"] = i.split("=")[1] if not data["port"]: return None return data def get_project_info(self, get): """设置项目日志是否开启""" try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.project_name)) project_data = self.get_project_stat(project_data) return json_response(True, data=project_data) # 上传版本 def upload_version(self, get): """ 上传压缩包并存储为版本 """ if not hasattr(get, 'sitename'): return json_response(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return json_response(False, '版本号不能为空') if not hasattr(get, 'ps'): get.ps = '' try: upload_files = os.path.join("/tmp", get.f_name) if "/www/server/panel/class" not in sys.path: sys.path.insert(0, "/www/server/panel/class") from files import files file_obj = files() ff = file_obj.upload(get) if type(ff) == int: return ff if not ff['status']: return json_response(False, ff['msg']) output_dir = str(os.path.join('/tmp', public.GetRandomString(16))) os.makedirs(output_dir, 777) is_jar_war = os.path.splitext(upload_files)[-1] in (".jar", ".war") if not self.extract_archive(upload_files, output_dir)[0] and not is_jar_war: return json_response(False, '解压失败,仅支持zip,tar.gz,tar,bz2,gz格式的压缩包') version_tool = VersionTool() if not is_jar_war: if len(os.listdir(output_dir)) == 1: real_output_dir = str(os.path.join(output_dir, os.listdir(output_dir)[0])) if os.path.isdir(real_output_dir): output_dir = real_output_dir res = version_tool.publish_by_src_path(get.sitename, output_dir, get.version, get.ps, sync=True) public.ExecShell('rm -rf {}'.format(output_dir)) public.ExecShell('rm -rf {}'.format(upload_files)) else: res = version_tool.publish_by_file(get.sitename, upload_files, get.version, get.ps) public.ExecShell('rm -rf {}'.format(upload_files)) if res is None: return public.returnResult(True, '添加成功') return json_response(False, '添加失败' + res) except: return json_response(False, traceback.format_exc()) @staticmethod def extract_archive(file_path, output_dir): try: import tarfile import zipfile import gzip import bz2 name = os.path.basename(file_path) if name.endswith('.tar.gz'): with tarfile.open(file_path, 'r:gz') as tar: tar.extractall(output_dir) elif name.endswith('.zip'): with zipfile.ZipFile(file_path, 'r') as zip_ref: zip_ref.extractall(output_dir) elif name.endswith('.gz'): with gzip.open(file_path, 'rb') as f_in, open(os.path.join(output_dir, name[:-3]), 'wb') as f_out: shutil.copyfileobj(f_in, f_out) elif name.endswith('.tar'): with tarfile.open(file_path, 'r') as tar: tar.extractall(output_dir) elif name.endswith('.bz2'): with open(file_path, 'rb') as f_in, open(os.path.join(output_dir, name[:-4]), 'wb') as f_out: with bz2.BZ2File(f_in) as bz: shutil.copyfileobj(bz, f_out) else: return False, '文件格式错误.' except: return False, '解压失败' return True, '解压成功' # 获取列表 @staticmethod def get_version_list(get): if not hasattr(get, 'sitename'): return public.returnResult(False, 'The project name cannot be empty') version_tool = VersionTool() return json_response(True, data=version_tool.version_list(get.sitename)) # 删除版本 @staticmethod def remove_version(get): if not hasattr(get, 'sitename'): return json_response(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return json_response(False, '版本号不能为空') version_tool = VersionTool() if version_tool.remove(get.sitename, get.version) is None: return public.returnResult(True, '删除成功') return json_response(False, '删除失败') # 恢复版本 def recover_version(self, get): try: if not hasattr(get, 'sitename'): return json_response(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return json_response(False, '版本号不能为空') project_data = self.get_project_find(get.sitename) if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.sitename)) version_tool = VersionTool() project_config = project_data['project_config'] # spring jar 包情况 if project_config["java_type"] == "springboot": v_info = version_tool.get_version_info(get.sitename, get.version) if not v_info: return json_response(False, 'The specified version does not exist: {}'.format(get.version)) path = os.path.join(version_tool.pack_path, v_info['zip_name']) if not os.path.isfile: return json_response(False, 'The specified version file is missing') if os.path.exists(project_config["project_jar"] + "_back"): os.remove(project_config["project_jar"] + "_back") if not path.endswith(".jar"): # 如果不是jar包,则解压并寻找jar包 output_dir = str(os.path.join('/tmp', public.GetRandomString(16))) os.makedirs(output_dir, 777) if not self.extract_archive(path, output_dir)[0]: return json_response(False, '解压失败') else: for f in os.listdir(output_dir): if f.endswith(".jar"): path = os.path.join(output_dir, f) break else: return json_response(False, '未找到jar包文件') shutil.move(project_config["project_jar"], project_config["project_jar"] + "_back") shutil.copyfile(path, project_config["project_jar"]) return json_response(True, "版本文件替换成功,重启后生效") # war 包 v_info = version_tool.get_version_info(get.sitename, get.version) if not v_info: return json_response(False, 'The specified version does not exist: {}'.format(get.version)) path = os.path.join(version_tool.pack_path, v_info['zip_name']) if path.endswith(".war") and os.path.isfile(project_data["path"]): # 如果是war包 if os.path.exists(project_data["path"] + "_back"): os.remove(project_data["path"] + "_back") shutil.move(project_data["path"], project_data["path"] + "_back") shutil.copyfile(path, project_data["path"]) return json_response(True, "版本文件替换成功,重启后生效") res = version_tool.recover(get.sitename, get.version, project_data['path']) if res is not True: return json_response(False, res) return json_response(True, '恢复成功') except: return json_response(False, traceback.format_exc()) def now_file_backup(self, get): try: if not hasattr(get, 'sitename'): return json_response(False, 'The project name cannot be empty') if not hasattr(get, 'version') or not get.version.strip(): return json_response(False, '版本号不能为空') else: get.version = get.version.strip() if not hasattr(get, 'ps'): get.ps = '' project_data = self.get_project_find(get.sitename) if not project_data: return json_response(False, 'The specified item does not exist: {}'.format(get.sitename)) path = project_data['path'] version_tool = VersionTool() project_config = project_data['project_config'] if project_config["java_type"] == "springboot": res = version_tool.publish_by_file(get.sitename, project_config["project_jar"], get.version, get.ps) else: if os.path.isdir(path): res = version_tool.publish_by_src_path(get.sitename, path, get.version, get.ps, sync=True) elif os.path.isfile(path): res = version_tool.publish_by_file(get.sitename, path, get.version, get.ps) else: return json_response(False, '添加失败') if res is None: return json_response(True, '添加成功') return json_response(False, '添加失败' + res) except: return json_response(False, traceback.format_exc()) @staticmethod def set_version_ps(get): if not hasattr(get, 'sitename'): return json_response(False, 'The project name cannot be empty') if not hasattr(get, 'version'): return json_response(False, '版本号不能为空') if not hasattr(get, 'ps'): get.ps = '' version_tool = VersionTool() res = version_tool.set_ps(get.sitename, get.version, get.ps) if not res: return json_response(False, '设置失败') return json_response(True, '设置成功') def change_log_path(self, get): """"修改日志文件地址 @author baozi <202-03-13> @param: get ( dict ): 请求: 包含项目名称和新的路径 @return """ try: project_data = self.get_project_find(get.project_name.strip()) new_log_path = get.path.strip().rstrip("/") except: return json_response(False, '参数错误') if not project_data: return json_response(False, 'The project does not exist') if not new_log_path.startswith('/'): return json_response(False, '路径格式错误') if not os.path.exists(new_log_path): os.makedirs(new_log_path, mode=0o777) project_config = project_data["project_config"] if project_config['java_type'] == 'springboot': project_config['logs'] = new_log_path + '/' + project_data["name"] + '.log' pdata = { 'name': project_data["name"], 'project_config': json.dumps(project_config) } public.M('sites').where('id=?', (project_data["id"],)).update(pdata) # 重启项目 res = self.restart_project(get) self.write_project_log('修改Java项目{}日志路径为:{}'.format(get.project_name, new_log_path)) return json_response(True, "项目日志路径修改成功") elif project_config['java_type'] == 'duli': project_config['logs'] = new_log_path + '/' tomcat = utils.site_tomcat(project_data["name"]) if not tomcat.change_log_path(new_log_path, project_data["name"].replace(".", "_")): return public.returnMsg(False, "项目日志路径修改失败") pdata = { 'name': project_data["name"], 'project_config': json.dumps(project_config) } public.M('sites').where('name=?', (get.project_name.strip(),)).update(pdata) # 重启项目 tomcat.restart() self.write_project_log('修改Java项目{}日志路径为:{}'.format(get.project_name, new_log_path)) return json_response(True, "项目日志路径修改成功") elif project_config['java_type'] == 'neizhi': tomcat = utils.bt_tomcat(project_config['tomcat_version']) if not tomcat.change_log_path(new_log_path, str(project_config['tomcat_version'])): return public.returnMsg(False, "项目日志路径修改失败") tomcat.restart() self.write_project_log('修改Java项目{}日志路径为:{}'.format(get.project_name, new_log_path)) return json_response(True, "项目日志路径修改成功") else: return json_response(False, "项目类型错误") def multi_remove_project(self, get): """ @name 批量删除项目 @author baozi<2023-3-2> @param get<dict_obj>{ project_names: list[string] <项目名称>所组成的列表 } @return dict """ try: project_names = get.project_names if isinstance(project_names, list): project_names = [i.strip() for i in project_names] else: project_names = [] except: return json_response(False, "Parameter error") if not project_names: return json_response(False, "未选中要删除的站点") projects = public.M('sites').where( 'project_type=? AND name in ({})'.format(",".join(["?"] * len(project_names))), ('Java', *project_names)).select() if not projects: return public.returnMsg(False, "未选中要删除的站点") _duli, _neizh, _springboot = [], [], [] 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) # 执行每种删除的独特操作 if _duli: self._multi_remove_duli(_duli) if _neizh: self._multi_remove_neizhi(_neizh) if _springboot: self._multi_remove_springboot(_springboot) # 清除Nginx, Apache 配置文件,并重起服务 for i in projects: remove_sites_service_config(i["name"], config_prefix="java_") # 从面板数据库删除信息 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('id IN ({})'.format(",".join(["?"] * len(project_ids))), project_ids).delete() self.write_project_log('批量删除Java项目:[{}]'.format("; ".join([i["name"] for i in projects]))) for project in projects: self.del_crontab(project["name"]) return json_response(True, "删除项目成功", data=[i["name"] for i in projects]) @staticmethod def _multi_remove_duli(projects): for project in projects: # 关闭独立项目 tomcat = utils.site_tomcat(project["name"]) if tomcat: tomcat.stop() if os.path.exists(tomcat.path): shutil.rmtree(tomcat.path) @staticmethod def _multi_remove_neizhi(projects): used_tomcat: Dict[int, utils.TomCat] = {} for project in projects: ver = int(project['project_config']['tomcat_version']) if ver in used_tomcat: tomcat = used_tomcat[ver] else: tomcat = utils.bt_tomcat(ver) if not tomcat: continue used_tomcat[ver] = tomcat tomcat.remove_host(project["name"]) for t in used_tomcat.values(): t.save_config_xml() t.restart() def _multi_remove_springboot(self, projects): for project in projects: # 停止项目 server_name = "spring_" + project["name"] + project.get("server_name_suffix", "") s_admin = RealServer() s_admin.daemon_admin(server_name, "stop") s_admin.del_daemon(server_name) project_config = project["project_config"] pid_file = project_config['pids'] if os.path.exists(pid_file): os.remove(pid_file) script_file = project_config['scripts'] if os.path.exists(script_file): os.remove(script_file) env_path = "{}/env/{}.env".format(self._java_project_vhost, project_config["project_name"]) if os.path.exists(env_path): os.remove(env_path) log_file = 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 """ try: project_names = get.project_names set_type = get.operation.strip() except: return json_response(False, "Parameter error") if set_type not in ["start", "stop"]: return public.returnMsg(False, "操作信息错误") if isinstance(project_names, list): project_names = [i.strip() for i in project_names] else: project_names = [] projects = public.M('sites').where( 'project_type=? AND name in ({})'.format(",".join(["?"] * len(project_names))), ('Java', *project_names) ).select() if not projects: return json_response(False, "未选中要启动的站点") project_names = [i["name"] for i in projects] spring_boot_projects = [] duli_tomcat = [] bt_tomcat = {} error_list = [] for project in projects: project['project_config'] = json.loads(project['project_config']) if project['project_config']['java_type'] == 'neizhi': ver = int(project['project_config']['tomcat_version']) if ver not in bt_tomcat: tomcat = utils.bt_tomcat(project['project_config']['tomcat_version']) if not tomcat: error_list.append({"project_name": project["name"], "msg": "启动失败,没有安装Tomcat{}".format( project['project_config']['tomcat_version'])}) project_names.remove(project["name"]) continue bt_tomcat[ver] = tomcat if project['project_config']['java_type'] == 'duli': tomcat = utils.site_tomcat(project["name"]) if tomcat: duli_tomcat.append(tomcat) if project['project_config']['java_type'] == 'springboot': spring_boot_projects.append(project) for t in itertools.chain(bt_tomcat.values(), duli_tomcat): if set_type == "start": t.start() else: t.stop() for i in spring_boot_projects: if set_type == "start": self.start_project(public.to_dict_obj({"project_name": i["name"]})) else: self.stop_project(public.to_dict_obj({"project_name": i["name"]})) if error_list: return json_response(True, msg="部分项目操作失败", data={ "error_list": error_list, "project_names": project_names }) return json_response(True, msg="启动成功" if set_type == "start" else "停止成功", data={ "project_names": project_names }) @staticmethod def del_crontab(project_name: str): """ @name 删除项目日志切割任务 @auther hezhihong<2022-10-31> @return """ cron_name = '[勿删]Java项目[{}]运行日志切割'.format(project_name) 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 get_load_info(self, get): try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, "未找到项目") pid = self.get_project_pid(project_data) if not pid: return json_response(False, "项目未启动") res = self.real_process.get_process_tree(pid) if isinstance(res["data"], list): res["data"] = {i.get("pid", "0"): i for i in res["data"]} return res def get_port_status(self, get): try: project_data = self.get_project_find(get.project_name.strip()) except: return json_response(False, '参数错误') if not project_data: return json_response(False, "未找到项目") pid = self.get_project_pid(project_data) if not pid: return json_response(False, "项目未启动") ports = [] try: p = psutil.Process(pid) for i in p.connections(): if i.status == "LISTEN" and i.laddr.port not in ports: ports.append(str(i.laddr.port)) except: pass if not ports: return json_response(False, "未找到端口") res = {str(i): { "port": i, "fire_wall": None, "nginx_proxy": None, } for i in ports} from firewallModelV2.comModel import main port_list = main().port_rules_list(get)['message'] for i in port_list: if str(i["Port"]) in res: res[str(i["Port"])]['fire_wall'] = i rsp = RealServerProxy(project_data) proxy_list = rsp.get_proxy_list() for i in proxy_list: if str(i["proxy_port"]) in res: res[str(i["proxy_port"])]['nginx_proxy'] = i return json_response(True, "获取成功", data=list(res.values())) def add_server_proxy(self, get): if not hasattr(get, "site_name") or not get.site_name.strip(): return json_response(status=False, msg="Parameter error") project_data = self.get_project_find(get.site_name) if not project_data: return json_response(False, "未找到项目") rp = RealServerProxy(project_data) proxy_data = rp.check_args(get, is_modify=False) if isinstance(proxy_data, str): return json_response(status=False, msg=proxy_data) # 使用正则匹配尝试添加 res = rp.create_proxy(proxy_data) if res is None: return json_response(status=True, msg="添加成功") # 尝试模板生成 proxy_info = project_data['project_config'].get("proxy_info", []) proxy_info.append(proxy_data) project_data['project_config']['proxy_info'] = proxy_info domain_list = self._project_domain_list(project_data['id']) domains = [(i["name"], str(i["port"])) for i in domain_list] ssl, f_ssl = self._get_ssl_status(project_data['name']) error_msg = self.create_config(project_data, domains, ssl, f_ssl) if not error_msg: public.serviceReload() pdata = { 'project_config': json.dumps(project_data['project_config']) } public.M("sites").where("id=?", (project_data['id'],)).update(pdata) return json_response(status=True, msg="添加成功") return json_response(status=False, msg=error_msg) def modify_server_proxy(self, get): if not hasattr(get, "site_name") or not get.site_name.strip(): return json_response(status=False, msg="Parameter error") project_data = self.get_project_find(get.site_name) if not project_data: return json_response(False, "未找到项目") rp = RealServerProxy(project_data) proxy_data = rp.check_args(get, is_modify=True) if isinstance(proxy_data, str): return json_response(status=False, msg=proxy_data) proxy_info = project_data['project_config'].get("proxy_info", []) idx = None for index, i in enumerate(proxy_info): if i["proxy_id"] == proxy_data["proxy_id"] and i["site_name"] == proxy_data["site_name"]: idx = index break if idx is None: return json_response(status=False, msg="未找到该id的反向代理配置") # 使用正则匹配尝试添加 res = rp.modify_proxy(proxy_data) if res is None: return json_response(status=True, msg="修改成功") # 尝试模板生成 proxy_info[idx] = proxy_data project_data['project_config']['proxy_info'] = proxy_info domain_list = self._project_domain_list(project_data['id']) domains = [(i["name"], str(i["port"])) for i in domain_list] ssl, f_ssl = self._get_ssl_status(project_data['name']) error_msg = self.create_config(proxy_data, domains, ssl, f_ssl) if not error_msg: public.serviceReload() pdata = { 'project_config': json.dumps(project_data['project_config']) } public.M("sites").where("id=?", (project_data['id'],)).update(pdata) return json_response(status=True, msg="修改成功") return json_response(status=False, msg=error_msg) def remove_server_proxy(self, get): try: site_name = get.site_name.strip() proxy_id = get.proxy_id.strip() except: return json_response(status=False, msg="Parameter error") project_data = self.get_project_find(site_name) if not project_data: return json_response(False, "未找到项目") rp = RealServerProxy(project_data) msg = rp.remove_proxy(site_name, proxy_id) if msg: return json_response(status=False, msg=msg) return json_response(status=True, msg="Successfully delete") def server_proxy_list(self, get): try: site_name = get.site_name.strip() except: return json_response(status=False, msg="Parameter error") project_data = self.get_project_find(site_name) if not project_data: return json_response(False, "未找到项目") _p = RealServerProxy(project_data) data = _p.get_proxy_list() return json_response(status=True, data=data) @staticmethod def check_env_for_project(get): project_cmd = "" by_process = 0 env_list = [] env_file = '' try: if hasattr(get, "project_cmd") and get.project_cmd: project_cmd = get.project_cmd.strip() project_jar = get.project_jar.strip() if hasattr(get, "by_process") and get.by_process: by_process = int(get.by_process) if hasattr(get, "env_list") and get.env_list: env_list = get.env_list if hasattr(get, "env_file") and get.env_file: env_file = get.env_file except: return json_response(status=False, msg="Parameter error") if not os.path.exists(project_jar): return json_response(status=False, msg="jar文件不存在") if env_file and not os.path.exists(env_file): return json_response(status=False, msg="环境变量文件不存在") spring_parser = SpringConfigParser( jar_path=project_jar, process=by_process, cmd=project_cmd, env_list=env_list, env_file=env_file, ) data = spring_parser.get_tip() if not data: return json_response(status=True, msg="未检测到配置问题", data=data) return json_response(status=True, data=data) def set_static_path(self, get): try: project_name = get.project_name.strip() project_data = self.get_project_find(project_name) status = utils.js_value_to_bool(get.status) index = get.index.strip() path = get.path.strip() except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目无法设置静态文件") proxy_info = project_data['project_config'].get("proxy_info", []) for i in proxy_info: if i["proxy_dir"] == "/": return json_response(status=False, msg="项目已存在根路由【/】配置,无法设置态文件配置") project_data["project_config"]["static_info"] = { "status": status, "index": index, "path": path, "use_try_file": True, } res = self._set_static_path(project_data) if isinstance(res, str): return json_response(status=False, msg=res) public.M("sites").where("id=?", (project_data["id"],)).update({ "project_config": json.dumps(project_data["project_config"]) }) return json_response(status=True, msg="Successfully set") def get_keep_status(self, get): try: project_name = get.project_name.strip() project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") from mod.project.java.project_update import ProjectUpdate if not project_data: return json_response(False, "未找到项目") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目不支持该功能") p = ProjectUpdate(project_name, project_data["project_config"]["project_jar"]) res = p.get_keep_status() return res def update_project_by_restart(self, get): try: project_name = get.project_name.strip() project_jar = get.project_jar.strip() project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目不支持该功能") from mod.project.java.project_update import ProjectUpdate p = ProjectUpdate(project_name, new_jar=project_jar) res = p.restart_update() return res def update_project_by_keep(self, get): now_port = 0 run_time = 0 try: project_name = get.project_name.strip() project_jar = get.project_jar.strip() if hasattr(get, "now_port") and get.now_port: now_port = int(get.now_port) if hasattr(get, "run_time") and get.run_time: run_time = int(get.run_time) project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目不支持该功能") if not os.path.isfile(project_jar): return json_response(status=False, msg="jar文件不存在") if public.get_webserver() != "nginx": return json_response(status=False, msg="当前只支持nginx使用") ng_file = "/www/server/panel/vhost/nginx/java_{}.conf".format(project_name) if not os.path.exists(ng_file): return json_response(status=False, msg="未启用外网访问的不能进行不停机更新") panel_path = "/www/server/panel" pid_file = "{}/keep/{}.pid".format(self._java_project_path, project_name) public.ExecShell( "nohup {}/pyenv/bin/python3 {}/mod/project/java/project_update.py {} {} {} {} &> /dev/null & \n" "echo $! > {} ".format( panel_path, panel_path, project_name, project_jar, now_port, run_time, pid_file) ) return json_response(status=True, msg="更新任务已开始") def force_stop(self, get): try: project_name = get.project_name.strip() project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") project_config = project_data["project_config"] pid_file = "{}/keep/{}.pid".format(self._java_project_path, project_name) pid_data = public.readFile(pid_file) if isinstance(pid_data, str) and pid_data != "0": try: p = psutil.Process(int(pid_data)) p.kill() except: pass service_list = [] rep_service = re.compile(r"^spring_%s_\S{8}$" % public.prevent_re_key(project_name), re.M) for i in os.scandir("/usr/lib/systemd/system"): if i.is_file() and rep_service.match(i.name): service_list.append(i.name) now_name = "spring_" + project_config["project_name"] + "_" + project_config.get("server_name_suffix", "") if now_name in service_list: service_list.remove(now_name) for i in service_list: public.ExecShell("systemctl stop {}".format(i)) os.remove("/usr/lib/systemd/system/{}".format(i)) public.ExecShell("systemctl daemon-reload") upstream_file = "/www/server/panel/vhost/nginx/java_{}_upstream.conf".format(project_name) if os.path.isfile(upstream_file): # 说明新旧同时存在 则删除旧的 upstream_data = public.readFile(upstream_file) if isinstance(upstream_data, str): old_upstream_data = re.search(r"server 127\.0\.0\.1:(?P<port>\d+);", upstream_data) if old_upstream_data: old_port = old_upstream_data.group("port") ng_file = "/www/server/panel/vhost/nginx/java_{}.conf".format(project_name) ng_data = public.readFile(ng_file) if not isinstance(ng_data, str): return "Nginx配置文件读取错误,无法取消轮询,使用新实例" new_config = ng_data.replace("{}_backend".format(project_name), "127.0.0.1:{}".format(old_port)) public.writeFile(ng_file, new_config) res = public.checkWebConfig() if res is not True: public.writeFile(ng_file, ng_data) else: os.remove(upstream_file) public.serviceReload() return json_response(status=True, msg="强制停止成功") def keep_option(self, get): try: project_name = get.project_name.strip() option = get.option.strip() project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") if option not in ("use_new", "use_old", "stop_new"): return json_response(status=False, msg="Parameter error") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目不支持该功能") from mod.project.java.project_update import ProjectUpdate p = ProjectUpdate(project_name, project_data["project_config"]["project_jar"]) res = p.keep_option(option) return res def get_spring_log_list(self, get): try: project_name = get.project_name.strip() project_data = self.get_project_find(project_name) except: return json_response(status=False, msg="Parameter error") if not project_data: return json_response(False, "未找到项目") if not project_data["project_config"]["java_type"] == "springboot": return json_response(status=False, msg="非springboot项目不支持该功能") pid = self.get_project_pid(project_data) project_config = project_data["project_config"] project_jar = project_config["project_jar"] project_cmd = project_config["project_cmd"] env_list = project_config["env_list"] env_file = project_config["env_file"] spring_log_parser = SpringLogConfigParser( jar_path=project_jar, process=pid, cmd=project_cmd, env_list=env_list, env_file=env_file, ) res = [] for i in spring_log_parser.get_all_log_ptah(): for j in os.scandir(i): if j.is_file() and j.name.endswith(".log"): log_path = os.path.join(i, j.name) res.append(log_path) return json_response(status=True, data=res) @staticmethod def get_spring_log_data(get): try: log_file = get.log_file.strip() except: return json_response(status=False, msg="Parameter error") if not os.path.isfile(log_file): return json_response(status=False, msg="日志文件不存在") return json_response(status=True, data=public.GetNumLines(log_file, 1000)) @staticmethod def install_jdk_new(get): if not hasattr(get, 'version') or not get.version.strip(): return json_response(False, '版本号不能为空') version = get.version.strip() if os.path.exists('/www/server/java/' + version): return json_response(False, '版本已经存在') jdk_manager = utils.JDKManager() if version not in jdk_manager.versions_list: return public.returnMsg(False, '版本号不存在') jdk_manager.async_install_jdk(version) return json_response(True, '已添加到安装任务,请在消息盒子中查看安装情况') @staticmethod def install_tomcat_new(get): java_path = None if not hasattr(get, 'version') or not get.version.strip(): return json_response(False, '版本号不能为空') version = get.version.strip() if hasattr(get, 'java_path') and get.java_path.strip(): java_path = get.java_path.strip() res = utils.TomCat.async_install_tomcat_new(version, java_path) if res is not None: return json_response(False, res) return json_response(True, '已添加到安装任务,请在消息盒子中查看安装情况')
Close