1170 lines
43 KiB
Python
1170 lines
43 KiB
Python
|
|
import copy
|
|||
|
|
import json
|
|||
|
|
import os.path
|
|||
|
|
import sys
|
|||
|
|
import time
|
|||
|
|
import psutil
|
|||
|
|
from typing import Optional, Dict, Union, List, Tuple, Any, Iterable
|
|||
|
|
|
|||
|
|
if "/www/server/panel/class" not in sys.path:
|
|||
|
|
sys.path.insert(0, "/www/server/panel/class")
|
|||
|
|
|
|||
|
|
import public
|
|||
|
|
|
|||
|
|
from mod.base import RealServer, json_response
|
|||
|
|
from mod.project.java import utils
|
|||
|
|
from mod.project.java.projectMod import debug, main as JavaProject
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Group:
|
|||
|
|
GROUP_DATA_DIR = "/www/server/panel/data/java_group"
|
|||
|
|
GROUP_TMP_DIR = "/var/tmp/springboot/group"
|
|||
|
|
|
|||
|
|
def __init__(self, group_id: Optional[str] = None, group_data: Optional[dict] = None):
|
|||
|
|
self.group_id = group_id
|
|||
|
|
if isinstance(group_data, dict):
|
|||
|
|
self.config: Optional[Dict[str, Union[str, List]]] = group_data
|
|||
|
|
else:
|
|||
|
|
self.config = self.load_group_data_by_id()
|
|||
|
|
|
|||
|
|
if not os.path.exists(self.GROUP_DATA_DIR):
|
|||
|
|
os.makedirs(self.GROUP_DATA_DIR, 0o600)
|
|||
|
|
|
|||
|
|
if not os.path.exists(self.GROUP_TMP_DIR):
|
|||
|
|
os.makedirs(self.GROUP_TMP_DIR)
|
|||
|
|
|
|||
|
|
self.running_data = {
|
|||
|
|
"length": 0, # 已完成的数量
|
|||
|
|
"remaining": 0, # 未完成的数量
|
|||
|
|
"executing": 0, # 正在执行的数量
|
|||
|
|
"projects": [], # 项目操作详情
|
|||
|
|
"msg": "", # 信息
|
|||
|
|
"status": True,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 如果有配置文件,则表示可以执行
|
|||
|
|
def can_running(self) -> bool:
|
|||
|
|
return isinstance(self.config, dict)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def new_group_id() -> str:
|
|||
|
|
from uuid import uuid4
|
|||
|
|
return uuid4().hex[::2]
|
|||
|
|
|
|||
|
|
# 从配置文件中加载数据
|
|||
|
|
def load_group_data_by_id(self) -> Optional[dict]:
|
|||
|
|
config_file = "{}/{}.json".format(self.GROUP_DATA_DIR, self.group_id)
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile(config_file))
|
|||
|
|
except:
|
|||
|
|
return None
|
|||
|
|
if isinstance(data, dict):
|
|||
|
|
return data
|
|||
|
|
else:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def save_group_data(self):
|
|||
|
|
if self.config:
|
|||
|
|
config_file = "{}/{}.json".format(self.GROUP_DATA_DIR, self.group_id)
|
|||
|
|
public.writeFile(config_file, json.dumps(self.config))
|
|||
|
|
|
|||
|
|
# 更新旧版数据
|
|||
|
|
@classmethod
|
|||
|
|
def update_group_data(cls) -> None:
|
|||
|
|
json_file = "/www/server/panel/class/projectModel/java_project_groups.json"
|
|||
|
|
if not os.path.isfile(json_file):
|
|||
|
|
return
|
|||
|
|
data_str = public.readFile(json_file)
|
|||
|
|
try:
|
|||
|
|
data = json.loads(data_str)
|
|||
|
|
except:
|
|||
|
|
os.remove(json_file)
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
java_projects = public.M("sites").where('project_type=?', ('Java',)).field("id,name").select()
|
|||
|
|
except:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
projects_dict = {i["name"]: i["id"] for i in java_projects}
|
|||
|
|
|
|||
|
|
for idx, i in enumerate(data):
|
|||
|
|
name = i.get("group_name", "默认分组-{}".format(idx + 1))
|
|||
|
|
projects = i.get("projects", [])
|
|||
|
|
order = i.get("order", []) # type: list
|
|||
|
|
tmp_p = []
|
|||
|
|
for p in projects:
|
|||
|
|
if p["project_name"] in projects_dict and p["project_name"] in order:
|
|||
|
|
tmp_p.append({
|
|||
|
|
"id": projects_dict[p["project_name"]],
|
|||
|
|
"name": p["project_name"],
|
|||
|
|
"level": order.index(p["project_name"]) + 1,
|
|||
|
|
"check_info": {
|
|||
|
|
"type": "port",
|
|||
|
|
"port": [],
|
|||
|
|
"wait_time": 180,
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if tmp_p:
|
|||
|
|
group_id = cls.new_group_id()
|
|||
|
|
public.writeFile(
|
|||
|
|
"{}/{}.json".format(cls.GROUP_DATA_DIR, group_id),
|
|||
|
|
json.dumps({
|
|||
|
|
"group_name": name,
|
|||
|
|
"projects": tmp_p,
|
|||
|
|
"sort_type": "sequence",
|
|||
|
|
})
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if os.path.isfile(json_file):
|
|||
|
|
os.remove(json_file)
|
|||
|
|
|
|||
|
|
# 检查数据
|
|||
|
|
def check_group_data(self) -> Optional[str]:
|
|||
|
|
"""
|
|||
|
|
一个组的格式
|
|||
|
|
group = {
|
|||
|
|
"group_name": "aaa",
|
|||
|
|
"projects": [
|
|||
|
|
{
|
|||
|
|
"id": 84,
|
|||
|
|
"name": "tduck-api",
|
|||
|
|
"level": 1,
|
|||
|
|
"check_info": {
|
|||
|
|
"type": ("port" or "active"),
|
|||
|
|
"port": [8456, 8511],
|
|||
|
|
"wait_time": 180,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"sort_type": ("simultaneous" or "sequence")
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
# 检查self.config是否为字典
|
|||
|
|
if not isinstance(self.config, dict):
|
|||
|
|
return "Parameter format error"
|
|||
|
|
|
|||
|
|
# 检查'sort_type'键是否存在且值为("simultaneous" or "sequence")
|
|||
|
|
if "sort_type" not in self.config or self.config["sort_type"] not in ("simultaneous", "sequence"):
|
|||
|
|
return "编排方式设置错误"
|
|||
|
|
|
|||
|
|
if 'group_name' not in self.config or not isinstance(self.config["group_name"], str) \
|
|||
|
|
or not self.config["group_name"]:
|
|||
|
|
return "分组名称设置错误"
|
|||
|
|
|
|||
|
|
# 检查projects键是否存在且为列表
|
|||
|
|
if "projects" not in self.config or not isinstance(self.config["projects"], list):
|
|||
|
|
return "项目列表设置错误"
|
|||
|
|
|
|||
|
|
# 遍历projects列表中的每个项目
|
|||
|
|
for project in self.config["projects"]:
|
|||
|
|
# 检查每个项目是否为字典
|
|||
|
|
if not isinstance(project, dict):
|
|||
|
|
return "项目列表设置错误"
|
|||
|
|
|
|||
|
|
# 检查'id', 'name', 'level', 'check_info'键是否存在
|
|||
|
|
if not all(key in project for key in ("id", "name", "level", "check_info")):
|
|||
|
|
return "项目项目配置信息缺失"
|
|||
|
|
|
|||
|
|
# 检查id、level是否为整数
|
|||
|
|
if not isinstance(project["id"], int) or not isinstance(project["level"], int):
|
|||
|
|
return "The Project ID or Priority parameter is in the wrong format"
|
|||
|
|
|
|||
|
|
# 检查'check_info'是否为字典
|
|||
|
|
if not isinstance(project["check_info"], dict):
|
|||
|
|
return "项目{}检查策略设置错误".format(project["name"])
|
|||
|
|
|
|||
|
|
# 检查'check_info'中的type, 'port', 'wait_time'
|
|||
|
|
if not all(key in project["check_info"] for key in ("type", "port", "wait_time")):
|
|||
|
|
return "项目{}检查策略信息缺失".format(project["name"])
|
|||
|
|
|
|||
|
|
# 检查type的值
|
|||
|
|
if project["check_info"]["type"] not in ("port", "active"):
|
|||
|
|
return "项目{}检查策略类型设置错误".format(project["name"])
|
|||
|
|
|
|||
|
|
# 如果所有检查都通过,则数据格式正确
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 执行 check_info 中的判断,返回现在的进程是否属于在运行中, 如果不是运行中, 就是异常
|
|||
|
|
@staticmethod
|
|||
|
|
def do_check_info(check_info: dict, process: psutil.Process):
|
|||
|
|
if check_info["type"] == "port":
|
|||
|
|
timeout = time.time() > process.create_time() + 60 * 3
|
|||
|
|
listen = []
|
|||
|
|
connections = process.connections()
|
|||
|
|
for connection in connections:
|
|||
|
|
if connection.status == "LISTEN":
|
|||
|
|
listen.append(connection.laddr.port)
|
|||
|
|
|
|||
|
|
if not check_info["port"]:
|
|||
|
|
if not timeout and not bool(listen):
|
|||
|
|
return "waiting"
|
|||
|
|
if not bool(listen):
|
|||
|
|
return 'failed'
|
|||
|
|
else:
|
|||
|
|
return 'succeeded'
|
|||
|
|
else:
|
|||
|
|
res = not bool(set(check_info["port"]) - set(listen)) # 如果所有的端口都在监听中,则返回True
|
|||
|
|
if not timeout and not res:
|
|||
|
|
return 'waiting'
|
|||
|
|
if res:
|
|||
|
|
return 'succeeded'
|
|||
|
|
else:
|
|||
|
|
return 'failed'
|
|||
|
|
else:
|
|||
|
|
create_time = process.create_time()
|
|||
|
|
if time.time() > create_time + int(check_info["wait_time"]):
|
|||
|
|
return "succeeded"
|
|||
|
|
else:
|
|||
|
|
return "waiting"
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def is_running(pid: int):
|
|||
|
|
try:
|
|||
|
|
return psutil.Process(pid).is_running()
|
|||
|
|
except:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 获取运行状态信息
|
|||
|
|
def run_status(self, last_write_time: float) -> dict:
|
|||
|
|
default_error = {
|
|||
|
|
"running": False,
|
|||
|
|
"msg": "操作出错,已退出",
|
|||
|
|
"running_data": None,
|
|||
|
|
"last_write_time": 0,
|
|||
|
|
}
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
log_file = "{}/{}.log".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
if not os.path.isfile(pid_file):
|
|||
|
|
return default_error
|
|||
|
|
try:
|
|||
|
|
pid = int(public.readFile(pid_file))
|
|||
|
|
except:
|
|||
|
|
return default_error
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile(log_file))
|
|||
|
|
except: # 如果读取出错,则说明进程出现问题,则杀死进程,并清除数据,返回错误
|
|||
|
|
if os.path.isfile(log_file):
|
|||
|
|
os.remove(log_file)
|
|||
|
|
if os.path.isfile(pid_file):
|
|||
|
|
os.remove(pid_file)
|
|||
|
|
if self.is_running(pid):
|
|||
|
|
psutil.Process(pid).kill()
|
|||
|
|
|
|||
|
|
return default_error
|
|||
|
|
|
|||
|
|
# 如果进程不在运行,则返回上一次运行的数据(防止卡顿导致导致最后的数据没有读取到)
|
|||
|
|
if not self.is_running(pid):
|
|||
|
|
return {
|
|||
|
|
"running": False,
|
|||
|
|
"msg": "操作进程已退出",
|
|||
|
|
"running_data": data,
|
|||
|
|
"last_write_time": os.path.getmtime(log_file),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 如果还在运行, 则进行长链接, 等待最多5秒, 如果没有数据被写入, 且进程依旧在运行,则返回上一次的数据;
|
|||
|
|
# 若不在运行则说明,且没有写入则说明等待期间出错了 (启动进程退出前必定会进行一次写入)
|
|||
|
|
# 如果有数据被写入则返回最新数据
|
|||
|
|
|
|||
|
|
for i in range(50):
|
|||
|
|
m_time = os.path.getmtime(log_file)
|
|||
|
|
if abs(m_time - last_write_time) > 0.001: # 如果时间差大于0.001秒,则说明数据再次被写入了,则退出循环,返回数据
|
|||
|
|
now_write_time = m_time
|
|||
|
|
break
|
|||
|
|
elif i == 49: # 最后一次检测后,直接退出循环
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
time.sleep(0.1)
|
|||
|
|
else: # 如果 5 秒内没有数据被写入,则返回上一次的数据
|
|||
|
|
if not self.is_running(pid): # 不在运行, 说明等待期间出错了
|
|||
|
|
if os.path.isfile(log_file):
|
|||
|
|
os.remove(log_file)
|
|||
|
|
if os.path.isfile(pid_file):
|
|||
|
|
os.remove(pid_file)
|
|||
|
|
return default_error
|
|||
|
|
|
|||
|
|
# 在运行,则返回上一次的数据
|
|||
|
|
return {
|
|||
|
|
"running": self.is_running(pid),
|
|||
|
|
"msg": "运行中",
|
|||
|
|
"running_data": data,
|
|||
|
|
"last_write_time": last_write_time,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile(log_file))
|
|||
|
|
except:
|
|||
|
|
if self.is_running(pid):
|
|||
|
|
psutil.Process(pid).kill()
|
|||
|
|
if os.path.isfile(log_file):
|
|||
|
|
os.remove(log_file)
|
|||
|
|
if os.path.isfile(pid_file):
|
|||
|
|
os.remove(pid_file)
|
|||
|
|
return {
|
|||
|
|
"running": False,
|
|||
|
|
"msg": "操作进程出错,已退出",
|
|||
|
|
"running_data": None,
|
|||
|
|
"last_write_time": 0,
|
|||
|
|
}
|
|||
|
|
running = self.is_running(pid)
|
|||
|
|
return {
|
|||
|
|
"running": running,
|
|||
|
|
"msg": "运行中" if running else "操作进程已结束",
|
|||
|
|
"running_data": data,
|
|||
|
|
"last_write_time": now_write_time,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 获取可操作状态的信息
|
|||
|
|
def get_operation_info(self) -> Tuple[Iterable[str], str]:
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
try:
|
|||
|
|
pid = int(public.readFile(pid_file))
|
|||
|
|
p = psutil.Process(pid)
|
|||
|
|
if not p.is_running():
|
|||
|
|
return ("start", "stop"), ""
|
|||
|
|
else:
|
|||
|
|
last_cmd = p.cmdline()[-2] if len(p.cmdline()) == 4 else ""
|
|||
|
|
return ("termination",), last_cmd
|
|||
|
|
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
return ("start", "stop"), ""
|
|||
|
|
|
|||
|
|
def group_info(self, project_cache: Optional[dict] = None) -> Optional[dict]:
|
|||
|
|
if not self.config:
|
|||
|
|
return
|
|||
|
|
if not project_cache:
|
|||
|
|
project_ids = [i["id"] for i in self.config["projects"]]
|
|||
|
|
if not project_ids:
|
|||
|
|
data = copy.deepcopy(self.config)
|
|||
|
|
data["group_id"] = self.group_id
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
projects = public.M('sites').where(
|
|||
|
|
'project_type=? and id IN ({})'.format(",".join(["?"] * len(project_ids))),
|
|||
|
|
('Java', *project_ids)).select()
|
|||
|
|
project_cache = {}
|
|||
|
|
for i in projects:
|
|||
|
|
i["project_config"] = json.loads(i["project_config"])
|
|||
|
|
project_cache[i["id"]] = i
|
|||
|
|
|
|||
|
|
j_pro = JavaProject()
|
|||
|
|
|
|||
|
|
res = copy.deepcopy(self.config)
|
|||
|
|
res["group_id"] = self.group_id
|
|||
|
|
res["operation_info"], res["now_operation"] = self.get_operation_info()
|
|||
|
|
running_num = 0
|
|||
|
|
for i in res["projects"]:
|
|||
|
|
if i["id"] in project_cache:
|
|||
|
|
try:
|
|||
|
|
listen = []
|
|||
|
|
pid = j_pro.get_project_pid(project_cache[i["id"]])
|
|||
|
|
p = psutil.Process(int(pid))
|
|||
|
|
connections = p.connections()
|
|||
|
|
for connection in connections:
|
|||
|
|
if connection.status == "LISTEN":
|
|||
|
|
listen.append(connection.laddr.port)
|
|||
|
|
except:
|
|||
|
|
i["running"] = False
|
|||
|
|
i["project_status"] = 'not_run'
|
|||
|
|
i["pid"] = None
|
|||
|
|
i["listen"] = []
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
running_num += 1
|
|||
|
|
i["running"] = True
|
|||
|
|
i["project_status"] = self.do_check_info(i["check_info"], p)
|
|||
|
|
i["pid"] = p.pid
|
|||
|
|
i["listen"] = listen
|
|||
|
|
|
|||
|
|
if not res["now_operation"]:
|
|||
|
|
all_num = len(res["projects"])
|
|||
|
|
if all_num == 0:
|
|||
|
|
res["operation_info"] = []
|
|||
|
|
else:
|
|||
|
|
if running_num == all_num:
|
|||
|
|
res["operation_info"] = ["stop"]
|
|||
|
|
if running_num == 0:
|
|||
|
|
res["operation_info"] = ["start"]
|
|||
|
|
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
# 运行一个Group相关的函数
|
|||
|
|
# ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
|
|||
|
|
def run_operation(self, operation: str) -> Optional[str]:
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
|
|||
|
|
if operation not in ("start", "stop"):
|
|||
|
|
return "指定的操作不存在"
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
p = psutil.Process(public.readFile(pid_file))
|
|||
|
|
if p.is_running():
|
|||
|
|
return "操作运行中, 请等待上一个操作执行完成"
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
if os.path.exists(pid_file):
|
|||
|
|
os.remove(pid_file)
|
|||
|
|
|
|||
|
|
self.build_run_sort(reverse=(operation == "stop"))
|
|||
|
|
self.save_running_data()
|
|||
|
|
panel_path = "/www/server/panel"
|
|||
|
|
public.ExecShell(
|
|||
|
|
"nohup {}/pyenv/bin/python3 {}/mod/project/java/group_script.py {} {} &> /tmp/group_script.log & \n"
|
|||
|
|
"echo $! > {} ".format(
|
|||
|
|
panel_path, panel_path, operation, self.group_id, pid_file)
|
|||
|
|
)
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def build_run_sort(self, reverse=False) -> List[List[dict]]:
|
|||
|
|
projects = self.config["projects"] # type: List[Dict[str, Union[int, str, dict]]]
|
|||
|
|
if self.config["sort_type"] == "simultaneous":
|
|||
|
|
projects_group = [projects]
|
|||
|
|
else:
|
|||
|
|
projects_group = []
|
|||
|
|
projects.sort(key=lambda x: x['level'])
|
|||
|
|
last_level = -1
|
|||
|
|
for i in projects:
|
|||
|
|
if i['level'] != last_level:
|
|||
|
|
last_level = i['level']
|
|||
|
|
projects_group.append([i])
|
|||
|
|
else:
|
|||
|
|
projects_group[-1].append(i)
|
|||
|
|
|
|||
|
|
self.running_data['length'] = len(projects)
|
|||
|
|
self.running_data['remaining'] = len(projects)
|
|||
|
|
for g in projects_group:
|
|||
|
|
names = [i["name"] for i in g]
|
|||
|
|
self.running_data["projects"].append({
|
|||
|
|
"names": names,
|
|||
|
|
"msg": "",
|
|||
|
|
"running": False,
|
|||
|
|
"data": {
|
|||
|
|
i["name"]: {"status": False, "msg": "", "pid": 0, "name": i["name"]}
|
|||
|
|
for i in g
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if reverse:
|
|||
|
|
self.running_data["projects"] = self.running_data["projects"][::-1]
|
|||
|
|
return projects_group[::-1]
|
|||
|
|
|
|||
|
|
return projects_group
|
|||
|
|
|
|||
|
|
# 真正执行启动的逻辑
|
|||
|
|
def real_run_start(self):
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
pid = os.getpid()
|
|||
|
|
public.writeFile(pid_file, str(pid))
|
|||
|
|
if not self.can_running():
|
|||
|
|
self.running_data["msg"] = "项目组配置文件错误,无法启动该项目组"
|
|||
|
|
self.running_data["status"] = False
|
|||
|
|
self.save_running_data()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 构建运行启动的信息,并返回运行顺序
|
|||
|
|
self.running_data["msg"] = "启动操作运行中"
|
|||
|
|
run_sort = self.build_run_sort(reverse=False)
|
|||
|
|
self.save_running_data()
|
|||
|
|
for idx, g in enumerate(run_sort):
|
|||
|
|
res_msg = self._run_start_one_step(g, sort_idx=idx)
|
|||
|
|
if isinstance(res_msg, str):
|
|||
|
|
self.running_data["msg"] = res_msg
|
|||
|
|
self.running_data["status"] = False
|
|||
|
|
self.save_running_data()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.running_data["msg"] = "启动操作运行成功"
|
|||
|
|
self.running_data["status"] = True
|
|||
|
|
self.save_running_data()
|
|||
|
|
|
|||
|
|
def save_running_data(self):
|
|||
|
|
log_file = "{}/{}.log".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
public.writeFile(log_file, json.dumps(self.running_data))
|
|||
|
|
|
|||
|
|
# 执行启动任务的每一个优先级中所有的项目
|
|||
|
|
def _run_start_one_step(self, projects: List[dict], sort_idx: int) -> Optional[str]:
|
|||
|
|
j_pro = JavaProject()
|
|||
|
|
|
|||
|
|
step_running_data = self.running_data["projects"][sort_idx] # type: Dict[str, Any]
|
|||
|
|
step_running_data["running"] = True
|
|||
|
|
step_running_data["msg"] = "正在启动【{}】项目".format(", ".join(step_running_data["names"]))
|
|||
|
|
self.running_data["remaining"] -= len(projects)
|
|||
|
|
self.running_data["executing"] = len(projects)
|
|||
|
|
self.save_running_data()
|
|||
|
|
|
|||
|
|
need_wait_project = []
|
|||
|
|
error_msg = None
|
|||
|
|
# 尝试启动每一个项目
|
|||
|
|
for p in projects:
|
|||
|
|
project_data = j_pro.get_project_find(p["name"])
|
|||
|
|
if not project_data:
|
|||
|
|
step_running_data["data"][p["name"]]["msg"] = "项目【{}】已丢失,无法启动".format(p["name"])
|
|||
|
|
continue
|
|||
|
|
project_pid = j_pro.get_project_pid(project_data)
|
|||
|
|
if project_pid:
|
|||
|
|
step_running_data["data"][p["name"]]["status"] = True
|
|||
|
|
step_running_data["data"][p["name"]]["msg"] = "项目【{}】已处于运行状态,未重新执行启动操作".format(
|
|||
|
|
p["name"])
|
|||
|
|
step_running_data["data"][p["name"]]["pid"] = project_pid
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
res = j_pro.start_spring_boot_project(project_data, wait=False) # 不等待启动成功
|
|||
|
|
if not res["status"]:
|
|||
|
|
step_running_data["data"][p["name"]]["status"] = False
|
|||
|
|
step_running_data["data"][p["name"]]["msg"] = "在执行启动项目【{}】指令的时出现错误:{}".format(
|
|||
|
|
p["name"], res["msg"])
|
|||
|
|
|
|||
|
|
error_msg = "出现无法处理的项目启动问题:" + res["msg"]
|
|||
|
|
break # 出现无法启动的项目,直接退出
|
|||
|
|
else:
|
|||
|
|
need_wait_project.append((project_data, p["check_info"]))
|
|||
|
|
|
|||
|
|
if error_msg:
|
|||
|
|
return error_msg
|
|||
|
|
|
|||
|
|
if not need_wait_project:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
self.save_running_data()
|
|||
|
|
time.sleep(0.5)
|
|||
|
|
while need_wait_project:
|
|||
|
|
remove_idx = []
|
|||
|
|
error_projects = []
|
|||
|
|
change = False
|
|||
|
|
for idx, (pd, check_info) in enumerate(need_wait_project):
|
|||
|
|
if "process" not in pd or not isinstance(pd["process"], psutil.Process):
|
|||
|
|
try:
|
|||
|
|
pid = j_pro.get_project_pid(pd)
|
|||
|
|
process = psutil.Process(int(pid))
|
|||
|
|
except:
|
|||
|
|
process = None
|
|||
|
|
else:
|
|||
|
|
process = pd["process"]
|
|||
|
|
|
|||
|
|
if not isinstance(process, psutil.Process) or not process.is_running():
|
|||
|
|
step_running_data["data"][pd["name"]]["status"] = False
|
|||
|
|
step_running_data["data"][pd["name"]]["msg"] = "项目【{}】启动失败,详细情况请查看日志".format(
|
|||
|
|
pd["name"])
|
|||
|
|
change = True
|
|||
|
|
remove_idx.append(idx)
|
|||
|
|
error_projects.append(pd["name"])
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
if step_running_data["data"][pd["name"]]["pid"] == 0:
|
|||
|
|
step_running_data["data"][pd["name"]]["pid"] = process.pid
|
|||
|
|
change = True
|
|||
|
|
|
|||
|
|
tmp_res = self.do_check_info(check_info, process)
|
|||
|
|
if tmp_res == "succeeded":
|
|||
|
|
step_running_data["data"][pd["name"]]["status"] = True
|
|||
|
|
step_running_data["data"][pd["name"]]["msg"] = "项目【{}】启动成功".format(pd["name"])
|
|||
|
|
remove_idx.append(idx)
|
|||
|
|
self.running_data["executing"] -= 1
|
|||
|
|
change = True
|
|||
|
|
elif tmp_res == "failed":
|
|||
|
|
step_running_data["data"][pd["name"]]["status"] = False
|
|||
|
|
step_running_data["data"][pd["name"]]["msg"] = "项目【{}】启动失败,详细情况请查看日志".format(
|
|||
|
|
pd["name"])
|
|||
|
|
remove_idx.append(idx)
|
|||
|
|
error_projects.append(pd["name"])
|
|||
|
|
change = True
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if remove_idx:
|
|||
|
|
for idx in remove_idx:
|
|||
|
|
need_wait_project.pop(idx)
|
|||
|
|
|
|||
|
|
if error_projects:
|
|||
|
|
return "项目【{}】启动失败无法继续执行启动操作,请查看日志".format(",".join(error_projects))
|
|||
|
|
if change is True:
|
|||
|
|
self.save_running_data()
|
|||
|
|
if need_wait_project:
|
|||
|
|
time.sleep(0.2)
|
|||
|
|
|
|||
|
|
step_running_data["running"] = False
|
|||
|
|
self.save_running_data()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
def real_run_stop(self):
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
pid = os.getpid()
|
|||
|
|
public.writeFile(pid_file, str(pid))
|
|||
|
|
if not self.can_running():
|
|||
|
|
self.running_data["msg"] = "项目组配置文件错误,无法停止该项目组"
|
|||
|
|
self.running_data["status"] = False
|
|||
|
|
self.save_running_data()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 构建运行启动的信息,并返回运行顺序
|
|||
|
|
self.running_data["msg"] = "项目组停止操作运行中"
|
|||
|
|
run_sort = self.build_run_sort(reverse=True)
|
|||
|
|
self.save_running_data()
|
|||
|
|
for idx, g in enumerate(run_sort):
|
|||
|
|
self._run_stop_one_step(g, sort_idx=idx)
|
|||
|
|
|
|||
|
|
self.running_data["msg"] = "停止操作运行成功"
|
|||
|
|
self.running_data["status"] = True
|
|||
|
|
self.save_running_data()
|
|||
|
|
|
|||
|
|
def _run_stop_one_step(self, projects: List[dict], sort_idx: int) -> None:
|
|||
|
|
j_pro = JavaProject()
|
|||
|
|
|
|||
|
|
step_running_data = self.running_data["projects"][sort_idx] # type: Dict[str, Any]
|
|||
|
|
step_running_data["running"] = True
|
|||
|
|
step_running_data["msg"] = "正在执行【{}】项目的停止任务".format(", ".join(step_running_data["names"]))
|
|||
|
|
self.running_data["remaining"] -= len(projects)
|
|||
|
|
self.running_data["executing"] = len(projects)
|
|||
|
|
|
|||
|
|
need_wait_project = []
|
|||
|
|
# 尝试停止每一个项目
|
|||
|
|
for p in projects:
|
|||
|
|
project_data = j_pro.get_project_find(p["name"])
|
|||
|
|
if not project_data:
|
|||
|
|
step_running_data["data"][p["name"]]["msg"] = "项目【】已丢失,无法执行停止操作"
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
project_pid = j_pro.get_project_pid(project_data)
|
|||
|
|
if not project_pid:
|
|||
|
|
step_running_data["data"][p["name"]]["status"] = True
|
|||
|
|
step_running_data["data"][p["name"]]["msg"] = "项目【{}】已停止".format(p["name"])
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
project_data["pid"] = project_pid
|
|||
|
|
|
|||
|
|
project_config = project_data["project_config"]
|
|||
|
|
server_name = "spring_" + project_config["project_name"] + project_config.get("server_name_suffix", "")
|
|||
|
|
s_admin = RealServer()
|
|||
|
|
if s_admin.daemon_status(server_name)["msg"] == "服务不存在!":
|
|||
|
|
j_pro.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"])
|
|||
|
|
need_wait_project.append((project_data, p["check_info"]))
|
|||
|
|
|
|||
|
|
if not need_wait_project:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
self.save_running_data()
|
|||
|
|
time.sleep(0.05)
|
|||
|
|
wait_num = 0
|
|||
|
|
while need_wait_project and wait_num < 10:
|
|||
|
|
remove_idx = []
|
|||
|
|
change = False
|
|||
|
|
for idx, (pd, check_info) in enumerate(need_wait_project):
|
|||
|
|
pid = pd["pid"]
|
|||
|
|
pid_info = j_pro.real_process.get_process_info_by_pid(pid)["data"]
|
|||
|
|
if not pid_info:
|
|||
|
|
step_running_data["data"][pd["name"]]["status"] = True
|
|||
|
|
step_running_data["data"][pd["name"]]["msg"] = "项目【{}】停止成功".format(pd["name"])
|
|||
|
|
remove_idx.append(idx)
|
|||
|
|
self.running_data["executing"] -= 1
|
|||
|
|
change = True
|
|||
|
|
|
|||
|
|
if remove_idx:
|
|||
|
|
for idx in remove_idx:
|
|||
|
|
need_wait_project.pop(idx)
|
|||
|
|
|
|||
|
|
if change is True:
|
|||
|
|
self.save_running_data()
|
|||
|
|
|
|||
|
|
wait_num += 1
|
|||
|
|
if need_wait_project:
|
|||
|
|
time.sleep(0.1)
|
|||
|
|
|
|||
|
|
step_running_data["running"] = False
|
|||
|
|
self.save_running_data()
|
|||
|
|
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
def termination_operation(self) -> None:
|
|||
|
|
pid_file = "{}/{}.pid".format(Group.GROUP_TMP_DIR, self.group_id)
|
|||
|
|
try:
|
|||
|
|
pid = int(public.readFile(pid_file))
|
|||
|
|
p = psutil.Process(pid)
|
|||
|
|
p.kill()
|
|||
|
|
os.remove(pid_file)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
class GroupMager:
|
|||
|
|
cache_type = ["springboot"]
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.project_cache: Optional[dict] = None
|
|||
|
|
|
|||
|
|
if not os.path.exists(Group.GROUP_DATA_DIR):
|
|||
|
|
os.makedirs(Group.GROUP_DATA_DIR, 0o600)
|
|||
|
|
|
|||
|
|
if not os.path.exists(Group.GROUP_TMP_DIR):
|
|||
|
|
os.makedirs(Group.GROUP_TMP_DIR)
|
|||
|
|
|
|||
|
|
def _get_project_cache(self):
|
|||
|
|
if self.project_cache is not None:
|
|||
|
|
return
|
|||
|
|
java_projects = public.M("sites").where('project_type=?', ('Java',)).select()
|
|||
|
|
_cache = {}
|
|||
|
|
for i in java_projects:
|
|||
|
|
config = json.loads(i["project_config"])
|
|||
|
|
if config["java_type"] in self.cache_type:
|
|||
|
|
i["project_config"] = config
|
|||
|
|
_cache[i["id"]] = i
|
|||
|
|
|
|||
|
|
self.project_cache = _cache
|
|||
|
|
|
|||
|
|
def group_list(self) -> List[dict]:
|
|||
|
|
group_list = []
|
|||
|
|
for i in os.listdir(Group.GROUP_DATA_DIR):
|
|||
|
|
file = "{}/{}".format(Group.GROUP_DATA_DIR, i)
|
|||
|
|
if os.path.isfile(file) and i.endswith(".json"):
|
|||
|
|
group_id = i[:-5]
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile(file))
|
|||
|
|
except:
|
|||
|
|
continue
|
|||
|
|
g = Group(group_id, data)
|
|||
|
|
group_list.append(g)
|
|||
|
|
|
|||
|
|
if not group_list:
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
self._get_project_cache()
|
|||
|
|
res = []
|
|||
|
|
for i in group_list:
|
|||
|
|
res.append(i.group_info(self.project_cache))
|
|||
|
|
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_group(data: dict) -> Optional[str]:
|
|||
|
|
g = Group(Group.new_group_id(), data)
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def remove_group(group_id: str) -> None:
|
|||
|
|
config_file = "{}/{}.json".format(Group.GROUP_DATA_DIR, group_id)
|
|||
|
|
if os.path.isfile(config_file):
|
|||
|
|
os.remove(config_file)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_project_to_group(group_id: str, project_name: str, check_info: dict, level: Optional[int]) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
p = public.M("sites").where('project_type=? AND name=?', ('Java', project_name)).find()
|
|||
|
|
if not p:
|
|||
|
|
return "指定项目【{}】不存在".format(project_name)
|
|||
|
|
project_config = json.loads(p["project_config"])
|
|||
|
|
if not project_config["java_type"] in GroupMager.cache_type:
|
|||
|
|
return "指定项目【{}】不是spring boot项目, 不支持添加到项目组".format(project_name)
|
|||
|
|
|
|||
|
|
used_project = [p["id"] for p in g.config["projects"]]
|
|||
|
|
if p["id"] in used_project:
|
|||
|
|
return "项目【{}】已存在于项目组【{}】".format(project_name, group_id)
|
|||
|
|
|
|||
|
|
if level is None:
|
|||
|
|
if not g.config["projects"]:
|
|||
|
|
level = 1
|
|||
|
|
else:
|
|||
|
|
level = max([p["level"] for p in g.config["projects"]]) + 1
|
|||
|
|
|
|||
|
|
g.config["projects"].append({
|
|||
|
|
"name": project_name,
|
|||
|
|
"id": p["id"],
|
|||
|
|
"check_info": check_info,
|
|||
|
|
"level": level,
|
|||
|
|
})
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_projects_to_group(group_id: str, project_ids: List[int]) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
project_list = public.M("sites").where(
|
|||
|
|
'project_type=? AND id IN ({})'.format(",".join(["?"] * len(project_ids))),
|
|||
|
|
('Java', *project_ids)
|
|||
|
|
).select()
|
|||
|
|
|
|||
|
|
used_project = [p["id"] for p in g.config["projects"]]
|
|||
|
|
start_level = max([p["level"] for p in g.config["projects"]] + [1]) # 最小值为1
|
|||
|
|
for p in project_list:
|
|||
|
|
if p["id"] in used_project:
|
|||
|
|
return "项目【{}】已存在于项目组【{}】".format(p["name"], group_id)
|
|||
|
|
project_config = json.loads(p["project_config"])
|
|||
|
|
if not project_config["java_type"] in GroupMager.cache_type:
|
|||
|
|
return "指定项目【{}】不是spring boot项目, 不支持添加到项目组".format(p["name"])
|
|||
|
|
|
|||
|
|
g.config["projects"].append({
|
|||
|
|
"name": p["name"],
|
|||
|
|
"id": p["id"],
|
|||
|
|
"check_info": {
|
|||
|
|
"type": "port",
|
|||
|
|
"port": [],
|
|||
|
|
"wait_time": 180,
|
|||
|
|
},
|
|||
|
|
"level": start_level + 1,
|
|||
|
|
})
|
|||
|
|
start_level += 1
|
|||
|
|
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def remove_project_from_group(group_id: str, project_id: int) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
target_idx = None
|
|||
|
|
for idx, p in enumerate(g.config["projects"]):
|
|||
|
|
if p["id"] == project_id:
|
|||
|
|
target_idx = idx
|
|||
|
|
break
|
|||
|
|
if target_idx is not None:
|
|||
|
|
g.config["projects"].pop(target_idx)
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group(group_id: str, group_data: dict) -> Optional[str]:
|
|||
|
|
g = Group(group_id, group_data)
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group_projects(group_id: str, project_datas: list) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
|
|||
|
|
project_ids = [p["id"] for p in project_datas]
|
|||
|
|
project_list = public.M("sites").where(
|
|||
|
|
'project_type=? AND id IN ({})'.format(",".join(["?"] * len(project_ids))),
|
|||
|
|
('Java', *project_ids)
|
|||
|
|
).select()
|
|||
|
|
|
|||
|
|
for p in project_list:
|
|||
|
|
project_config = json.loads(p["project_config"])
|
|||
|
|
if not project_config["java_type"] in GroupMager.cache_type:
|
|||
|
|
return "指定项目【{}】不是spring boot项目, 不支持设置到项目组".format(p["name"])
|
|||
|
|
|
|||
|
|
g.config["projects"] = project_datas
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group_project(group_id: str, project_id: int,
|
|||
|
|
check_info: Optional[dict], level: Optional[int]) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
p = public.M("sites").where('project_type=? AND id=?', ('Java', project_id)).find()
|
|||
|
|
if not p:
|
|||
|
|
return "The specified item does not exist"
|
|||
|
|
|
|||
|
|
target_idx = None
|
|||
|
|
for idx, p in enumerate(g.config["projects"]):
|
|||
|
|
if p["id"] == project_id:
|
|||
|
|
target_idx = idx
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if target_idx is None:
|
|||
|
|
return "指定项目不在该项目组内"
|
|||
|
|
update_data = {}
|
|||
|
|
if check_info is not None:
|
|||
|
|
update_data["check_info"] = check_info
|
|||
|
|
if level is not None:
|
|||
|
|
update_data["level"] = level
|
|||
|
|
|
|||
|
|
g.config["projects"][target_idx].update(update_data)
|
|||
|
|
|
|||
|
|
res = g.check_group_data()
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def change_sort_type(group_id: str, sort_type: str) -> Optional[str]:
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return "项目组不存在"
|
|||
|
|
|
|||
|
|
if sort_type not in ("simultaneous", "sequence"):
|
|||
|
|
return "排序方式错误"
|
|||
|
|
g.config["sort_type"] = sort_type
|
|||
|
|
g.save_group_data()
|
|||
|
|
|
|||
|
|
|
|||
|
|
Group.update_group_data()
|
|||
|
|
|
|||
|
|
|
|||
|
|
class main:
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def group_list(get):
|
|||
|
|
return GroupMager().group_list()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def group_info(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return json_response(status=False, msg="项目组不存在")
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, data=g.group_info())
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_group(get):
|
|||
|
|
try:
|
|||
|
|
group_name = get.group_name.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager().add_group({
|
|||
|
|
"group_name": group_name,
|
|||
|
|
"sort_type": "simultaneous",
|
|||
|
|
"projects": [],
|
|||
|
|
})
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="添加成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def remove_group(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
GroupMager.remove_group(group_id)
|
|||
|
|
return json_response(status=True, msg="Successfully delete")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_project_to_group(get):
|
|||
|
|
check_info = {
|
|||
|
|
"type": "port",
|
|||
|
|
"port": [],
|
|||
|
|
"wait_time": 180,
|
|||
|
|
}
|
|||
|
|
level = None
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
project_name = get.project_name.strip()
|
|||
|
|
if hasattr(get, "check_info") and get.check_info:
|
|||
|
|
check_info = json.loads(get.check_info)
|
|||
|
|
if hasattr(get, "level") and get.level:
|
|||
|
|
level = int(get.level)
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.add_project_to_group(group_id, project_name, check_info, level)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="添加成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def add_projects_to_group(get):
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
if hasattr(get, "project_ids") and isinstance(get.project_ids, str):
|
|||
|
|
project_ids = json.loads(get.project_ids)
|
|||
|
|
else:
|
|||
|
|
if isinstance(get.project_ids, list):
|
|||
|
|
project_ids = get.project_ids
|
|||
|
|
else:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.add_projects_to_group(group_id, project_ids)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="添加成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def remove_project_from_group(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
project_id = int(get.project_id)
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.remove_project_from_group(group_id, project_id)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="Successfully delete")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
if isinstance(get.group_data, str):
|
|||
|
|
group_data = json.loads(get.group_data)
|
|||
|
|
else:
|
|||
|
|
group_data = get.group_data
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.modify_group(group_id, group_data)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="修改成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group_project(get):
|
|||
|
|
check_info = None
|
|||
|
|
level = None
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
project_id = int(get.project_id)
|
|||
|
|
if hasattr(get, "check_info") and get.check_info:
|
|||
|
|
check_info = json.loads(get.check_info)
|
|||
|
|
if hasattr(get, "level") and get.level:
|
|||
|
|
level = int(get.level)
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.modify_group_project(group_id, project_id, check_info, level)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="修改成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def modify_group_projects(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
if isinstance(get.project_datas, str):
|
|||
|
|
project_datas = json.loads(get.project_datas)
|
|||
|
|
else:
|
|||
|
|
project_datas = get.project_datas
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.modify_group_projects(group_id, project_datas)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="修改成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def change_sort_type(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
sort_type = get.sort_type.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
res = GroupMager.change_sort_type(group_id, sort_type)
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="修改成功")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def start_group(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return json_response(status=False, msg="项目组不存在")
|
|||
|
|
|
|||
|
|
res = g.run_operation("start")
|
|||
|
|
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="启动进行中")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def stop_group(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return json_response(status=False, msg="项目组不存在")
|
|||
|
|
|
|||
|
|
res = g.run_operation("stop")
|
|||
|
|
|
|||
|
|
if isinstance(res, str):
|
|||
|
|
return json_response(status=False, msg=res)
|
|||
|
|
else:
|
|||
|
|
return json_response(status=True, msg="停止进行中")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_run_status(get):
|
|||
|
|
last_write_time = 0
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
if hasattr(get, "last_write_time") and get.last_write_time:
|
|||
|
|
last_write_time = float(get.last_write_time)
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
|
|||
|
|
g = Group(group_id)
|
|||
|
|
if not g.config:
|
|||
|
|
return json_response(status=False, msg="项目组不存在")
|
|||
|
|
|
|||
|
|
run_status = g.run_status(last_write_time)
|
|||
|
|
run_status["running_step"] = None
|
|||
|
|
if isinstance(run_status, dict):
|
|||
|
|
if isinstance(run_status["running_data"], dict) and "projects" in run_status["running_data"]:
|
|||
|
|
projects = run_status["running_data"]["projects"]
|
|||
|
|
for i in projects:
|
|||
|
|
if i["running"] is True:
|
|||
|
|
run_status["running_step"] = i
|
|||
|
|
|
|||
|
|
return json_response(status=True, data=run_status)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def termination_operation(get):
|
|||
|
|
try:
|
|||
|
|
group_id = get.group_id.strip()
|
|||
|
|
except:
|
|||
|
|
return json_response(status=False, msg="Parameter error")
|
|||
|
|
Group(group_id).termination_operation()
|
|||
|
|
return json_response(status=True, msg="operate successfully")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def spring_projects(get):
|
|||
|
|
java_projects = public.M("sites").where('project_type=?', ('Java',)).field("name,id,project_config").select()
|
|||
|
|
res = []
|
|||
|
|
for i in java_projects:
|
|||
|
|
config = json.loads(i["project_config"])
|
|||
|
|
if config["java_type"] in GroupMager.cache_type:
|
|||
|
|
res.append({
|
|||
|
|
"name": i["name"],
|
|||
|
|
"id": i["id"]
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return res
|