完善nginx标签。使用unix套接字。增加远程命令的运行和显示。
This commit is contained in:
194
gunicorn_tab.py
194
gunicorn_tab.py
@@ -436,6 +436,116 @@ class GunicornLogThread(QThread):
|
||||
self.result_ready.emit(False, error_msg)
|
||||
logger.error(f"Gunicorn服务日志查看异常: {error_msg}")
|
||||
|
||||
class GunicornLogCheckThread(QThread):
|
||||
"""检查并创建Gunicorn日志文件目录和文件的线程"""
|
||||
result_ready = Signal(bool, str)
|
||||
|
||||
def __init__(self, ssh_client, username, git_url, password):
|
||||
super().__init__()
|
||||
self.ssh_client = ssh_client
|
||||
self.username = username
|
||||
self.git_url = git_url
|
||||
self.password = password
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
# 从git_url中提取项目名(去掉.git后缀)
|
||||
project_name = self.git_url.split('/')[-1].replace('.git', '')
|
||||
logger.info(f"从git_url提取的项目名: {project_name}")
|
||||
|
||||
# 构建日志目录路径
|
||||
log_dir = f"/home/{self.username}/{project_name}/logs"
|
||||
access_log_path = f"{log_dir}/gunicorn_access.log"
|
||||
error_log_path = f"{log_dir}/gunicorn_error.log"
|
||||
|
||||
logger.info(f"检查日志目录: {log_dir}")
|
||||
|
||||
# 检查并创建日志目录
|
||||
check_dir_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S mkdir -p {log_dir}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(check_dir_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"创建日志目录失败: {error}")
|
||||
logger.error(f"创建日志目录失败: {error}")
|
||||
return
|
||||
|
||||
# 设置日志目录权限
|
||||
chmod_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S chmod 755 {log_dir}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(chmod_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"设置日志目录权限失败: {error}")
|
||||
logger.error(f"设置日志目录权限失败: {error}")
|
||||
return
|
||||
|
||||
# 检查并创建访问日志文件
|
||||
check_access_log_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S touch {access_log_path}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(check_access_log_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"创建访问日志文件失败: {error}")
|
||||
logger.error(f"创建访问日志文件失败: {error}")
|
||||
return
|
||||
|
||||
# 设置访问日志文件权限
|
||||
chmod_access_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S chmod 644 {access_log_path}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(chmod_access_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"设置访问日志文件权限失败: {error}")
|
||||
logger.error(f"设置访问日志文件权限失败: {error}")
|
||||
return
|
||||
|
||||
# 检查并创建错误日志文件
|
||||
check_error_log_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S touch {error_log_path}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(check_error_log_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"创建错误日志文件失败: {error}")
|
||||
logger.error(f"创建错误日志文件失败: {error}")
|
||||
return
|
||||
|
||||
# 设置错误日志文件权限
|
||||
chmod_error_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S chmod 644 {error_log_path}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(chmod_error_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"设置错误日志文件权限失败: {error}")
|
||||
logger.error(f"设置错误日志文件权限失败: {error}")
|
||||
return
|
||||
|
||||
# 设置日志文件所有者为用户
|
||||
chown_cmd = f"bash -c 'echo \"{self.password}\" | sudo -S chown -R {self.username}:{self.username} {log_dir}'"
|
||||
stdin, stdout, stderr = self.ssh_client.exec_command(chown_cmd)
|
||||
exit_status = stdout.channel.recv_exit_status()
|
||||
|
||||
if exit_status != 0:
|
||||
error = stderr.read().decode()
|
||||
self.result_ready.emit(False, f"设置日志文件所有者失败: {error}")
|
||||
logger.error(f"设置日志文件所有者失败: {error}")
|
||||
return
|
||||
|
||||
result_msg = f"日志目录和文件创建成功:\n目录: {log_dir}\n访问日志: {access_log_path}\n错误日志: {error_log_path}"
|
||||
self.result_ready.emit(True, result_msg)
|
||||
logger.info("日志目录和文件创建成功")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
self.result_ready.emit(False, error_msg)
|
||||
logger.error(f"检查并创建日志文件异常: {error_msg}")
|
||||
|
||||
class ServerControlThread(QThread):
|
||||
"""控制服务器设置的线程"""
|
||||
result_ready = Signal(bool, str)
|
||||
@@ -578,6 +688,11 @@ class GunicornTab(QWidget):
|
||||
self.view_logs_btn.clicked.connect(self.view_service_logs)
|
||||
service_btn_layout.addWidget(self.view_logs_btn)
|
||||
|
||||
# 检查日志文件按钮
|
||||
self.check_log_files_btn = QPushButton("检查日志文件")
|
||||
self.check_log_files_btn.clicked.connect(self.check_log_files)
|
||||
service_btn_layout.addWidget(self.check_log_files_btn)
|
||||
|
||||
service_layout.addLayout(service_btn_layout)
|
||||
layout.addLayout(service_layout)
|
||||
|
||||
@@ -628,27 +743,19 @@ class GunicornTab(QWidget):
|
||||
def init_service_content(self):
|
||||
"""初始化服务文件内容"""
|
||||
default_content = "[Unit]\n"
|
||||
default_content += "Description=Gunicorn daemon for myproject\n"
|
||||
default_content += "Description=Gunicorn Daemon for statuspage Project\n"
|
||||
default_content += "After=network.target\n\n"
|
||||
default_content += "[Service]\n"
|
||||
default_content += "User=【用户名】\n"
|
||||
default_content += "Group=【用户名】\n"
|
||||
default_content += "WorkingDirectory=【Django路径】\n"
|
||||
default_content += "# 所有Gunicorn参数直接在这里配置\n"
|
||||
default_content += "ExecStart=/usr/bin/gunicorn \\ \n"
|
||||
default_content += " --pythonpath 【Django路径】 \\ \n"
|
||||
default_content += " --bind 127.0.0.1:8000 \\ \n"
|
||||
default_content += " --workers $(nproc) \\ \n"
|
||||
default_content += " --worker-class sync \\ \n"
|
||||
default_content += " --timeout 60 \\ \n"
|
||||
default_content += " --name 【项目名】 \\ \n"
|
||||
default_content += " --access-logfile 【Django路径】/logs/gunicorn_access.log \\ \n"
|
||||
default_content += " --error-logfile 【Django路径】/logs/gunicorn_error.log \\ \n"
|
||||
default_content += " --log-level info \\ \n"
|
||||
default_content += " 【项目名】.wsgi:application\n"
|
||||
default_content += "Restart=on-failure\n"
|
||||
default_content += "RestartSec=5s\n"
|
||||
default_content += "PrivateTmp=true\n\n"
|
||||
default_content += "# 以xiaji用户运行(确保对/home/xiaji有完全权限)\n"
|
||||
default_content += "User=xiaji\n"
|
||||
default_content += "Group=xiaji\n"
|
||||
default_content += "# 项目工作目录\n"
|
||||
default_content += "WorkingDirectory=/home/xiaji/webstatus\n\n"
|
||||
default_content += "# 启动前预处理:先删除旧socket(避免残留),再创建目录(如果不存在)\n"
|
||||
default_content += "ExecStartPre=/bin/rm -f /home/xiaji/webstatus/sock/gunicorn.sock\n"
|
||||
default_content += "ExecStartPre=/bin/mkdir -p /home/xiaji/webstatus/sock\n\n"
|
||||
default_content += "# 单行ExecStart(无反斜杠,避免格式错误)\n"
|
||||
default_content += "ExecStart=/usr/bin/gunicorn --pythonpath /home/xiaji/webstatus --workers 3 --bind unix:/home/xiaji/webstatus/sock/gunicorn.sock --access-logfile /home/xiaji/webstatus/logs/gunicorn_access.log --error-logfile /home/xiaji/webstatus/logs/gunicorn_error.log statuspage.wsgi:application\n\n"
|
||||
default_content += "[Install]\n"
|
||||
default_content += "WantedBy=multi-user.target"
|
||||
|
||||
@@ -964,6 +1071,55 @@ class GunicornTab(QWidget):
|
||||
logger.error(f"Gunicorn服务日志查看失败: {message}")
|
||||
QMessageBox.warning(self, "错误", f"Gunicorn服务日志查看失败: {message}")
|
||||
|
||||
def check_log_files(self):
|
||||
"""检查并创建Gunicorn日志文件目录和文件"""
|
||||
if not self.ssh_client:
|
||||
self.append_output("错误: 未连接到服务器")
|
||||
return
|
||||
|
||||
if not self.username:
|
||||
self.append_output("错误: 未设置用户名")
|
||||
return
|
||||
|
||||
# 读取config.json获取git_url
|
||||
try:
|
||||
import json
|
||||
with open('config.json', 'r', encoding='utf-8') as f:
|
||||
config = json.load(f)
|
||||
# 获取第一个服务器的配置
|
||||
server_config = next(iter(config.values()))
|
||||
git_url = server_config.get('git_url', '')
|
||||
if not git_url:
|
||||
self.append_output("错误: config.json中未找到git_url")
|
||||
return
|
||||
except Exception as e:
|
||||
self.append_output(f"错误: 读取config.json失败: {str(e)}")
|
||||
return
|
||||
|
||||
# 请求用户输入sudo密码
|
||||
dialog = PasswordDialog(self)
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
password = dialog.get_password()
|
||||
self.append_output("正在检查并创建Gunicorn日志文件目录和文件...")
|
||||
|
||||
# 创建并启动日志检查线程
|
||||
self.log_check_thread = GunicornLogCheckThread(self.ssh_client, self.username, git_url, password)
|
||||
self.log_check_thread.result_ready.connect(self.on_log_check_result)
|
||||
self.log_check_thread.start()
|
||||
else:
|
||||
self.append_output("用户取消了密码输入")
|
||||
|
||||
def on_log_check_result(self, success, message):
|
||||
"""处理日志检查结果"""
|
||||
if success:
|
||||
self.append_output(message)
|
||||
logger.info("Gunicorn日志文件检查和创建成功")
|
||||
QMessageBox.information(self, "成功", "Gunicorn日志文件检查和创建成功")
|
||||
else:
|
||||
self.append_output(f"检查并创建日志文件失败: {message}")
|
||||
logger.error(f"Gunicorn日志文件检查和创建失败: {message}")
|
||||
QMessageBox.warning(self, "错误", f"Gunicorn日志文件检查和创建失败: {message}")
|
||||
|
||||
def on_control_result(self, success, message):
|
||||
"""处理控制结果"""
|
||||
if success:
|
||||
|
||||
Reference in New Issue
Block a user