修改了Gunicorn标签内容

This commit is contained in:
2025-08-28 22:30:17 +08:00
parent d559a85feb
commit 59b1f0e92a
13 changed files with 752 additions and 128 deletions

View File

@@ -2,19 +2,52 @@ import os
from loguru import logger
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QComboBox, QMessageBox, QTextEdit,
QGroupBox, QGridLayout, QProgressBar)
QGroupBox, QGridLayout, QProgressBar, QDialog,
QDialogButtonBox)
from PySide6.QtCore import Qt
from threads import (GunicornInstallThread, GunicornTestThread,
UploadGunicornServiceThread, ManageGunicornServiceThread)
class PasswordDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("输入密码")
self.setMinimumWidth(300)
layout = QVBoxLayout()
# 密码输入
password_layout = QHBoxLayout()
password_layout.addWidget(QLabel("密码:"))
self.password_input = QLineEdit()
self.password_input.setEchoMode(QLineEdit.Password)
password_layout.addWidget(self.password_input)
layout.addLayout(password_layout)
# 按钮
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
layout.addWidget(button_box)
self.setLayout(layout)
def get_password(self):
return self.password_input.text()
class GunicornTab(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
self.init_ui()
# 连接服务器切换信号
if self.parent and hasattr(self.parent, 'server_changed'):
self.parent.server_changed.connect(self.on_server_changed)
logger.info("Gunicorn标签已连接到服务器切换信号")
def init_ui(self):
layout = QVBoxLayout()
@@ -120,32 +153,130 @@ class GunicornTab(QWidget):
self.load_gunicorn_config()
def load_gunicorn_config(self):
if self.parent and hasattr(self.parent, 'server_connection_tab'):
django_path = self.parent.server_connection_tab.django_path_input.text()
self.django_path_input.setText(django_path)
# 生成默认的服务文件内容
service_name = self.service_name_input.text()
port = self.port_input.text()
workers = self.workers_input.text()
service_content = self.generate_service_file(service_name, django_path, port, workers)
self.service_editor.setText(service_content)
"""加载Gunicorn配置使用config.json中的值"""
try:
if self.parent and hasattr(self.parent, 'get_current_config'):
config = self.parent.get_current_config()
if config:
django_path = config.get('django_path', '')
project_name = config.get('project_name', 'myproject')
username = config.get('username', 'www-data')
# 设置Django项目路径
self.django_path_input.setText(django_path)
# 设置服务名称为项目名
self.service_name_input.setText(project_name)
# 生成服务文件内容
service_content = self.generate_service_file_from_config(config)
self.service_editor.setText(service_content)
logger.info(f"从当前服务器配置加载Gunicorn配置: django_path={django_path}, project_name={project_name}")
else:
logger.warning("未找到当前服务器配置")
else:
# 兼容旧的加载方式
config_path = os.path.join(os.path.dirname(__file__), 'config.json')
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
if config and 'servers' in config and len(config['servers']) > 0:
server_config = config['servers'][0]
django_path = server_config.get('remote_directory', '')
project_name = server_config.get('project_name', 'myproject')
username = server_config.get('username', 'www-data')
# 设置Django项目路径
self.django_path_input.setText(django_path)
# 设置服务名称为项目名
self.service_name_input.setText(project_name)
# 生成服务文件内容
service_content = self.generate_service_file_from_config(server_config)
self.service_editor.setText(service_content)
logger.info(f"从配置文件加载Gunicorn配置: django_path={django_path}, project_name={project_name}")
except Exception as e:
logger.error(f"加载Gunicorn配置失败: {str(e)}")
# 不显示警告,避免影响用户体验
def generate_service_file(self, service_name, django_path, port, workers):
def generate_service_file_from_config(self, config):
"""根据config.json配置生成服务文件内容"""
username = config.get('username', 'www-data')
project_name = config.get('project_name', 'myproject')
django_path = config.get('remote_directory', '/home/user')
# 构建完整的项目路径
project_path = f"{django_path.rstrip('/')}/{project_name}"
return f"""[Unit]
Description={service_name} daemon
Description=Gunicorn daemon for {project_name}
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory={django_path}
ExecStart=/usr/local/bin/gunicorn --workers {workers} --bind 0.0.0.0:{port} {os.path.basename(django_path)}.wsgi:application
User={username}
Group={username}
WorkingDirectory={project_path}
# 所有Gunicorn参数直接在这里配置
ExecStart=/usr/local/bin/gunicorn \\
--bind 127.0.0.1:8000 \\
--workers $(nproc --all * 2 + 1) \\
--worker-class sync \\
--timeout 60 \\
--name {project_name} \\
--access-logfile {project_path}/logs/gunicorn_access.log \\
--error-logfile {project_path}/logs/gunicorn_error.log \\
--log-level info \\
{project_name}.wsgi:application
Restart=on-failure
RestartSec=5s
PrivateTmp=true
[Install]
WantedBy=multi-user.target
"""
WantedBy=multi-user.target"""
def generate_service_file(self, service_name, django_path, port, workers):
"""保持向后兼容的方法"""
# 获取config.json中的配置信息
config = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
config = self.parent.server_connection_tab.get_current_config()
if config:
return self.generate_service_file_from_config(config)
else:
# 如果没有config使用默认值
username = 'www-data'
project_name = service_name
project_path = f"{django_path.rstrip('/')}/{project_name}"
return f"""[Unit]
Description=Gunicorn daemon for {project_name}
After=network.target
[Service]
User={username}
Group={username}
WorkingDirectory={project_path}
# 所有Gunicorn参数直接在这里配置
ExecStart=/usr/local/bin/gunicorn \\
--bind 127.0.0.1:{port} \\
--workers $(nproc --all * 2 + 1) \\
--worker-class sync \\
--timeout 60 \\
--name {project_name} \\
--access-logfile {project_path}/logs/gunicorn_access.log \\
--error-logfile {project_path}/logs/gunicorn_error.log \\
--log-level info \\
{project_name}.wsgi:application
Restart=on-failure
RestartSec=5s
PrivateTmp=true
[Install]
WantedBy=multi-user.target"""
def check_ssh_connection(self):
if not self.parent or not self.parent.ssh_client:
@@ -153,6 +284,25 @@ WantedBy=multi-user.target
return False
return True
def get_password(self):
# 获取密码
password = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
password = self.parent.server_connection_tab.password_input.text()
# 如果密码为空,弹出密码输入对话框
if not password:
dialog = PasswordDialog(self)
if dialog.exec_() == QDialog.Accepted:
password = dialog.get_password()
# 保存密码到服务器连接标签页
if self.parent and hasattr(self.parent, 'server_connection_tab'):
self.parent.server_connection_tab.password_input.setText(password)
else:
return None
return password
def install_gunicorn(self):
if not self.check_ssh_connection():
return
@@ -163,9 +313,11 @@ WantedBy=multi-user.target
self.progress_bar.setValue(0)
# 获取密码
password = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
password = self.parent.server_connection_tab.password_input.text()
password = self.get_password()
if password is None:
self.install_gunicorn_btn.setEnabled(True)
self.progress_bar.setVisible(False)
return
self.gunicorn_install_thread = GunicornInstallThread(self.parent.ssh_client, password)
self.gunicorn_install_thread.progress_updated.connect(self.update_progress)
@@ -218,20 +370,32 @@ WantedBy=multi-user.target
if not self.check_ssh_connection():
return
service_name = self.service_name_input.text().strip()
# 获取config.json中的配置信息
config = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
config = self.parent.server_connection_tab.get_current_config()
if config:
project_name = config.get('project_name', 'django')
else:
project_name = 'django'
# 使用gunicorn_[project_name].service格式作为服务名称
service_name = f"gunicorn_{project_name}"
service_content = self.service_editor.toPlainText()
if not service_name or not service_content:
QMessageBox.warning(self, "警告", "输入服务名称并编辑服务文件内容")
QMessageBox.warning(self, "警告", "请编辑服务文件内容")
return
self.output_text.append(f"正在上传服务文件 {service_name}...")
self.upload_service_btn.setEnabled(False)
# 获取密码
password = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
password = self.parent.server_connection_tab.password_input.text()
password = self.get_password()
if password is None:
self.upload_service_btn.setEnabled(True)
return
self.upload_thread = UploadGunicornServiceThread(self.parent.ssh_client, service_name, service_content, password)
self.upload_thread.result_ready.connect(self.on_upload_service_result)
@@ -250,10 +414,18 @@ WantedBy=multi-user.target
if not self.check_ssh_connection():
return
service_name = self.service_name_input.text().strip()
if not service_name:
QMessageBox.warning(self, "警告", "请输入服务名称")
return
# 获取config.json中的配置信息
config = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
config = self.parent.server_connection_tab.get_current_config()
if config:
project_name = config.get('project_name', 'django')
else:
project_name = 'django'
# 使用gunicorn_[project_name].service格式作为服务名称
service_name = f"gunicorn_{project_name}"
self.output_text.append(f"正在执行服务 {action} 操作...")
@@ -264,9 +436,11 @@ WantedBy=multi-user.target
btn.setEnabled(False)
# 获取密码
password = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
password = self.parent.server_connection_tab.password_input.text()
password = self.get_password()
if password is None:
for btn in buttons:
btn.setEnabled(True)
return
self.manage_thread = ManageGunicornServiceThread(self.parent.ssh_client, service_name, action, password)
self.manage_thread.result_ready.connect(lambda s, m: self.on_manage_service_result(s, m, buttons))
@@ -291,8 +465,17 @@ WantedBy=multi-user.target
if not self.check_ssh_connection():
return
service_name = self.service_name_input.text().strip()
if not service_name:
return
# 获取config.json中的配置信息
config = None
if self.parent and hasattr(self.parent, 'server_connection_tab'):
config = self.parent.server_connection_tab.get_current_config()
if config:
project_name = config.get('project_name', 'django')
else:
project_name = 'django'
# 使用gunicorn_[project_name].service格式作为服务名称
service_name = f"gunicorn_{project_name}"
self.manage_service("status")