From 59b1f0e92a29003b74d1c666d71a820c6b63d5d7 Mon Sep 17 00:00:00 2001 From: xiaji Date: Thu, 28 Aug 2025 22:30:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86Gunicorn=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/django_tab.cpython-38.pyc | Bin 8678 -> 9544 bytes __pycache__/gunicorn_tab.cpython-38.pyc | Bin 9305 -> 13060 bytes __pycache__/remote_command_tab.cpython-38.pyc | Bin 9168 -> 8739 bytes .../server_connection_tab.cpython-38.pyc | Bin 6358 -> 6884 bytes __pycache__/threads.cpython-38.pyc | Bin 22664 -> 24141 bytes app.log | 343 ++++++++++++++++++ config.json | 2 +- django_tab.py | 33 +- gunicorn_tab.py | 259 +++++++++++-- main.py | 7 +- remote_command_tab.py | 100 +++-- server_connection_tab.py | 26 +- threads.py | 110 +++++- 13 files changed, 752 insertions(+), 128 deletions(-) diff --git a/__pycache__/django_tab.cpython-38.pyc b/__pycache__/django_tab.cpython-38.pyc index d59d2e6b911d208bba5d88a47cd867e5284756b2..ebcc56beecd5e4850cd8641eedd0a70ebd9b8f5c 100644 GIT binary patch delta 3085 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 O1o3~sbDn0g&-)K?63{0A diff --git a/__pycache__/gunicorn_tab.cpython-38.pyc b/__pycache__/gunicorn_tab.cpython-38.pyc index eb54d6fd3520944a98cc6760cf94560dfe44ec26..4bbe000142f5ebe46ba360bb5fb341f7aca1247a 100644 GIT binary patch literal 13060 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 literal 9168 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 c@=4-t?dVsf48Bgh($ diff --git a/__pycache__/server_connection_tab.cpython-38.pyc b/__pycache__/server_connection_tab.cpython-38.pyc index 813705a675ea966ea79f0307711226029a320a83..56d9d9fa378083e8a1aa48308089cea2b1766ce1 100644 GIT binary patch delta 1969 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 HBYOM~o~Ih; diff --git a/app.log b/app.log index eb7d455..aaa2968 100644 --- a/app.log +++ b/app.log @@ -65,3 +65,346 @@ sudo: a password is required 2025-08-28 20:37:01.109 | INFO | __main__::114 - 应用程序启动 2025-08-28 20:41:24.800 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 20:51:01.943 | INFO | __main__::114 - 应用程序启动 +2025-08-28 20:51:04.428 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 20:51:05.201 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:51:05.730 | ERROR | threads:run:836 - 服务状态查询失败: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper +sudo: a password is required + +2025-08-28 20:51:05.734 | ERROR | gunicorn_tab:on_manage_service_result:285 - 服务操作失败: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper +sudo: a password is required + +2025-08-28 20:52:55.800 | INFO | __main__::114 - 应用程序启动 +2025-08-28 20:52:58.689 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 20:52:59.622 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:53:05.630 | ERROR | threads:run:836 - 服务状态查询失败: [sudo] password for xiaji: Unit django_gunicorn.service could not be found. + +2025-08-28 20:53:05.631 | ERROR | gunicorn_tab:on_manage_service_result:338 - 服务操作失败: [sudo] password for xiaji: Unit django_gunicorn.service could not be found. + +2025-08-28 20:54:39.385 | INFO | __main__::114 - 应用程序启动 +2025-08-28 20:54:45.328 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 20:54:46.326 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:54:53.497 | INFO | threads:run:862 - 执行服务管理命令: systemctl status django_gunicorn +2025-08-28 20:54:53.505 | ERROR | threads:run:871 - 服务文件不存在: /etc/systemd/system/django_gunicorn.service, 错误: ls: cannot access '/etc/systemd/system/django_gunicorn.service': No such file or directory + +2025-08-28 20:54:53.507 | ERROR | gunicorn_tab:on_manage_service_result:338 - 服务操作失败: 服务文件不存在: django_gunicorn.service +2025-08-28 21:00:17.337 | INFO | remote_command_tab:on_list_directory_result:186 - 目录列表成功 +2025-08-28 21:00:17.337 | INFO | threads:run:157 - 目录列表成功: /home/xiaji/ +2025-08-28 21:00:56.560 | ERROR | threads:run:559 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:00:56.560 | ERROR | django_tab:on_check_django_status_result:274 - Django状态检查失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:01:14.969 | INFO | threads:run:157 - 目录列表成功: /home/xiaji/ +2025-08-28 21:01:14.969 | INFO | remote_command_tab:on_list_directory_result:186 - 目录列表成功 +2025-08-28 21:01:28.149 | ERROR | threads:run:559 - Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:01:28.149 | ERROR | django_tab:on_check_django_status_result:274 - Django状态检查失败: Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:01:32.368 | ERROR | threads:run:363 - Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:01:32.370 | ERROR | django_tab:on_test_django_result:167 - Django测试启动失败: Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:01:36.279 | INFO | threads:run:304 - Django已安装: 5.2.5 +2025-08-28 21:01:36.280 | INFO | django_tab:on_install_django_result:135 - Django安装成功: Django已安装: 5.2.5 +2025-08-28 21:01:39.699 | ERROR | threads:run:363 - Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:01:39.700 | ERROR | django_tab:on_test_django_result:167 - Django测试启动失败: Django项目不存在: /home/xiaji/statuspage/ +2025-08-28 21:02:37.594 | INFO | server_connection_tab:save_config:34 - 配置文件保存成功 +2025-08-28 21:02:47.403 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:03:06.423 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:03:13.531 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:03:18.362 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:06:04.148 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:06:04.183 | ERROR | remote_command_tab:load_git_config:113 - 加载git配置失败: [Errno 2] No such file or directory: 'C:\\Users\\xiaji\\Documents\\个人文件夹\\夏骥\\config.json' +2025-08-28 21:06:32.121 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:06:32.155 | ERROR | remote_command_tab:load_git_config:113 - 加载git配置失败: 'gbk' codec can't decode byte 0xa8 in position 56: illegal multibyte sequence +2025-08-28 21:06:47.698 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:06:47.729 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:06:52.075 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:08:17.090 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:08:17.130 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:08:17.131 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/statuspage +2025-08-28 21:12:20.285 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:12:28.603 | ERROR | django_tab:on_test_django_result:184 - Django测试启动失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:12:28.603 | ERROR | threads:run:363 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:13:22.162 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:13:22.202 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:13:22.203 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/statuspage +2025-08-28 21:13:27.903 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:13:39.808 | ERROR | threads:run:363 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:13:39.809 | ERROR | django_tab:on_test_django_result:184 - Django测试启动失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:13:48.684 | INFO | threads:run:157 - 目录列表成功: /home/xiaji/ +2025-08-28 21:13:48.688 | INFO | remote_command_tab:on_list_directory_result:199 - 目录列表成功 +2025-08-28 21:16:20.769 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:16:20.810 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:16:20.811 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/statuspage +2025-08-28 21:16:22.780 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:16:25.519 | ERROR | threads:run:363 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:16:25.519 | ERROR | django_tab:on_test_django_result:184 - Django测试启动失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 21:16:29.049 | INFO | threads:run:157 - 目录列表成功: /home/xiaji/ +2025-08-28 21:16:29.051 | INFO | remote_command_tab:on_list_directory_result:199 - 目录列表成功: +total 176 +drwxr-x--- 9 xiaji xiaji 4096 Aug 27 20:52 . +drwxr-xr-x 3 root root 4096 Aug 27 04:10 .. +drwx------ 3 xiaji xiaji 4096 Aug 26 22:21 .cache +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 22:18 db.sqlite3 +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 22:18 .git +drwxrwxr-x 3 xiaji xiaji 4096 Aug 27 20:51 home +drwxrwxr-x 4 xiaji xiaji 4096 Aug 26 22:25 .local +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 22:18 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 22:18 requirements.txt +drwxrwxr-x 3 xiaji xiaji 4096 Aug 27 20:52 static +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 22:18 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 28 04:20 statuspage +-rw-r--r-- 1 xiaji xiaji 0 Aug 27 20:03 .sudo_as_admin_successful + +2025-08-28 21:17:03.711 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:17:03.777 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:17:03.782 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/statuspage +2025-08-28 21:17:09.386 | INFO | server_connection_tab:save_config:34 - 配置文件保存成功 +2025-08-28 21:17:11.652 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:17:16.174 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:17:18.319 | ERROR | django_tab:on_test_django_result:184 - Django测试启动失败: 依赖安装失败: error: externally-managed-environment + +× This environment is externally managed +╰─> To install Python packages system-wide, try apt install + python3-xyz, where xyz is the package you are trying to + install. + + If you wish to install a non-Debian-packaged Python package, + create a virtual environment using python3 -m venv path/to/venv. + Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make + sure you have python3-full installed. + + If you wish to install a non-Debian packaged Python application, + it may be easiest to use pipx install xyz, which will manage a + virtual environment for you. Make sure you have pipx installed. + + See /usr/share/doc/python3.12/README.venv for more information. + +note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages. +hint: See PEP 668 for the detailed specification. + +2025-08-28 21:17:18.319 | ERROR | threads:run:381 - 依赖安装失败: error: externally-managed-environment + +× This environment is externally managed +╰─> To install Python packages system-wide, try apt install + python3-xyz, where xyz is the package you are trying to + install. + + If you wish to install a non-Debian-packaged Python package, + create a virtual environment using python3 -m venv path/to/venv. + Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make + sure you have python3-full installed. + + If you wish to install a non-Debian packaged Python application, + it may be easiest to use pipx install xyz, which will manage a + virtual environment for you. Make sure you have pipx installed. + + See /usr/share/doc/python3.12/README.venv for more information. + +note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages. +hint: See PEP 668 for the detailed specification. + +2025-08-28 21:17:50.278 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:17:50.317 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:17:50.319 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:18:00.995 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:18:02.871 | INFO | threads:run:304 - Django已安装: 5.2.5 +2025-08-28 21:18:02.873 | INFO | django_tab:on_install_django_result:152 - Django安装成功: Django已安装: 5.2.5 +2025-08-28 21:19:24.402 | ERROR | threads:run:381 - 依赖安装失败: +2025-08-28 21:19:36.038 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:19:36.077 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:19:36.079 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:19:39.142 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:21:54.132 | INFO | server_connection_tab:save_config:34 - 配置文件保存成功 +2025-08-28 21:23:22.197 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:23:22.228 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:23:22.229 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:23:24.309 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:26:27.449 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:26:27.484 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:26:27.485 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:26:29.358 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:26:39.130 | INFO | threads:run:397 - Django测试服务器启动成功 +2025-08-28 21:26:39.131 | INFO | django_tab:on_test_django_result:181 - Django测试启动成功: Django测试服务器启动成功 +2025-08-28 21:26:52.767 | INFO | threads:run:598 - Django状态检查完成 +2025-08-28 21:26:52.786 | INFO | django_tab:on_check_django_status_result:288 - Django状态检查成功 +2025-08-28 21:26:56.002 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 21:27:03.503 | INFO | threads:run:867 - 执行服务管理命令: systemctl status django_gunicorn +2025-08-28 21:27:03.511 | ERROR | threads:run:876 - 服务文件不存在: /etc/systemd/system/django_gunicorn.service, 错误: ls: cannot access '/etc/systemd/system/django_gunicorn.service': No such file or directory + +2025-08-28 21:27:03.512 | ERROR | gunicorn_tab:on_manage_service_result:338 - 服务操作失败: 服务文件不存在: django_gunicorn.service +2025-08-28 21:27:54.858 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 21:28:00.516 | INFO | threads:run:867 - 执行服务管理命令: systemctl status django_gunicorn +2025-08-28 21:28:00.525 | ERROR | threads:run:876 - 服务文件不存在: /etc/systemd/system/django_gunicorn.service, 错误: ls: cannot access '/etc/systemd/system/django_gunicorn.service': No such file or directory + +2025-08-28 21:28:00.527 | ERROR | gunicorn_tab:on_manage_service_result:338 - 服务操作失败: 服务文件不存在: django_gunicorn.service +2025-08-28 21:28:02.915 | ERROR | threads:run:702 - wsgi.py文件不存在: /home/xiaji///wsgi.py +2025-08-28 21:28:02.916 | ERROR | gunicorn_tab:on_test_gunicorn_result:265 - Gunicorn测试失败: wsgi.py文件不存在: /home/xiaji///wsgi.py +2025-08-28 21:45:10.338 | INFO | __main__::114 - 应用程序启动 +2025-08-28 21:45:10.373 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 21:45:10.374 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 21:45:12.542 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 21:45:14.597 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 21:45:18.259 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 21:45:18.269 | ERROR | threads:run:884 - 服务文件不存在: /etc/systemd/system/gunicorn_django.service, 错误: ls: cannot access '/etc/systemd/system/gunicorn_django.service': No such file or directory + +2025-08-28 21:45:18.270 | ERROR | gunicorn_tab:on_manage_service_result:386 - 服务操作失败: 服务文件不存在: gunicorn_django.service +2025-08-28 21:45:26.168 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 21:45:30.745 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 21:45:30.754 | ERROR | threads:run:884 - 服务文件不存在: /etc/systemd/system/gunicorn_django.service, 错误: ls: cannot access '/etc/systemd/system/gunicorn_django.service': No such file or directory + +2025-08-28 21:45:30.755 | ERROR | gunicorn_tab:on_manage_service_result:386 - 服务操作失败: 服务文件不存在: gunicorn_django.service +2025-08-28 22:01:41.803 | INFO | __main__::114 - 应用程序启动 +2025-08-28 22:01:41.845 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:01:41.846 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 22:01:43.842 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:01:44.537 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 22:01:48.082 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 22:01:48.090 | ERROR | threads:run:884 - 服务文件不存在: /etc/systemd/system/gunicorn_django.service, 错误: ls: cannot access '/etc/systemd/system/gunicorn_django.service': No such file or directory + +2025-08-28 22:01:48.091 | ERROR | gunicorn_tab:on_manage_service_result:386 - 服务操作失败: 服务文件不存在: gunicorn_django.service +2025-08-28 22:01:55.720 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 22:01:59.324 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 22:01:59.333 | ERROR | threads:run:884 - 服务文件不存在: /etc/systemd/system/gunicorn_django.service, 错误: ls: cannot access '/etc/systemd/system/gunicorn_django.service': No such file or directory + +2025-08-28 22:01:59.334 | ERROR | gunicorn_tab:on_manage_service_result:386 - 服务操作失败: 服务文件不存在: gunicorn_django.service +2025-08-28 22:04:31.027 | INFO | __main__::114 - 应用程序启动 +2025-08-28 22:04:31.062 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:04:31.063 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 22:05:26.599 | INFO | __main__::114 - 应用程序启动 +2025-08-28 22:05:26.631 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:05:26.632 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 22:05:28.618 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:05:29.755 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 22:05:34.219 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 22:05:34.227 | ERROR | threads:run:884 - 服务文件不存在: /etc/systemd/system/gunicorn_django.service, 错误: ls: cannot access '/etc/systemd/system/gunicorn_django.service': No such file or directory + +2025-08-28 22:05:34.229 | ERROR | gunicorn_tab:on_manage_service_result:424 - 服务操作失败: 服务文件不存在: gunicorn_django.service +2025-08-28 22:06:09.440 | INFO | threads:run:756 - 准备上传服务文件: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:09.454 | INFO | threads:run:763 - 临时服务文件创建成功: /tmp/gunicorn_django.service +2025-08-28 22:06:09.477 | INFO | threads:run:781 - 服务文件移动成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:09.538 | INFO | threads:run:799 - 服务文件权限设置成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:09.590 | INFO | threads:run:807 - 服务文件验证成功: -rw-r--r-- 1 xiaji xiaji 705 Aug 28 22:06 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:09.888 | INFO | threads:run:831 - systemd重新加载成功 +2025-08-28 22:06:10.453 | INFO | threads:run:839 - 服务被systemd识别: gunicorn_django.service disabled enabled +2025-08-28 22:06:10.454 | INFO | threads:run:847 - 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:10.456 | INFO | gunicorn_tab:on_upload_service_result:373 - 服务文件上传成功: 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:20.044 | INFO | threads:run:875 - 执行服务管理命令: systemctl restart gunicorn_django +2025-08-28 22:06:20.059 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 705 Aug 28 22:06 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:06:20.139 | INFO | threads:run:920 - 服务restart成功: gunicorn_django +2025-08-28 22:06:20.140 | INFO | gunicorn_tab:on_manage_service_result:421 - 服务操作成功: 服务restart成功: gunicorn_django +2025-08-28 22:07:59.648 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:07:59.692 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:07:59.697 | INFO | django_tab:load_django_path:117 - 从配置文件加载django路径: /home/xiaji/ +2025-08-28 22:08:02.096 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:10:45.949 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:10:45.986 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:10:45.987 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/ +2025-08-28 22:10:45.987 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:10:53.292 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:13:07.349 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:13:07.387 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:13:07.388 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/ +2025-08-28 22:13:07.390 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:13:07.391 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:13:09.561 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:13:22.767 | INFO | threads:run:756 - 准备上传服务文件: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:22.782 | INFO | threads:run:763 - 临时服务文件创建成功: /tmp/gunicorn_django.service +2025-08-28 22:13:22.803 | INFO | threads:run:781 - 服务文件移动成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:22.865 | INFO | threads:run:799 - 服务文件权限设置成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:22.917 | INFO | threads:run:807 - 服务文件验证成功: -rw-r--r-- 1 xiaji xiaji 778 Aug 28 22:13 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:23.219 | INFO | threads:run:831 - systemd重新加载成功 +2025-08-28 22:13:23.845 | INFO | threads:run:839 - 服务被systemd识别: gunicorn_django.service disabled enabled +2025-08-28 22:13:23.846 | INFO | threads:run:847 - 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:23.847 | INFO | gunicorn_tab:on_upload_service_result:377 - 服务文件上传成功: 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:28.149 | INFO | threads:run:875 - 执行服务管理命令: systemctl restart gunicorn_django +2025-08-28 22:13:28.158 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 778 Aug 28 22:13 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:13:28.228 | INFO | threads:run:920 - 服务restart成功: gunicorn_django +2025-08-28 22:13:28.230 | INFO | gunicorn_tab:on_manage_service_result:425 - 服务操作成功: 服务restart成功: gunicorn_django +2025-08-28 22:15:05.213 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:15:05.248 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:15:05.249 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/ +2025-08-28 22:15:05.249 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:15:05.250 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:15:08.328 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:18:00.966 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:18:01.005 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:18:01.007 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/ +2025-08-28 22:18:01.007 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:18:01.008 | INFO | gunicorn_tab:load_gunicorn_config:175 - 从当前服务器配置加载Gunicorn配置: django_path=/home/xiaji/, project_name=statuspage +2025-08-28 22:18:01.009 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:18:03.033 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:18:10.456 | INFO | threads:run:707 - 找到wsgi.py文件: /home/xiaji/statuspage/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/handlers/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/asgiref/wsgi.py +2025-08-28 22:18:15.531 | ERROR | threads:run:732 - Gunicorn测试失败 +2025-08-28 22:18:15.531 | ERROR | gunicorn_tab:on_test_gunicorn_result:367 - Gunicorn测试失败: Gunicorn测试失败 +2025-08-28 22:18:21.513 | INFO | threads:run:707 - 找到wsgi.py文件: /home/xiaji/statuspage/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/handlers/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/asgiref/wsgi.py +2025-08-28 22:18:26.582 | ERROR | threads:run:732 - Gunicorn测试失败 +2025-08-28 22:18:26.585 | ERROR | gunicorn_tab:on_test_gunicorn_result:367 - Gunicorn测试失败: Gunicorn测试失败 +2025-08-28 22:20:04.518 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:20:04.553 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:20:04.556 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/statuspage +2025-08-28 22:20:04.556 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:20:04.558 | INFO | gunicorn_tab:load_gunicorn_config:175 - 从当前服务器配置加载Gunicorn配置: django_path=/home/xiaji/statuspage, project_name=statuspage +2025-08-28 22:20:04.559 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:20:12.042 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:20:15.094 | ERROR | threads:run:689 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 22:20:15.095 | ERROR | gunicorn_tab:on_test_gunicorn_result:367 - Gunicorn测试失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 22:20:24.016 | INFO | threads:run:707 - 找到wsgi.py文件: /home/xiaji/statuspage/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/handlers/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/asgiref/wsgi.py +2025-08-28 22:20:59.164 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:20:59.201 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:20:59.203 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/statuspage +2025-08-28 22:20:59.203 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:20:59.204 | INFO | gunicorn_tab:load_gunicorn_config:175 - 从当前服务器配置加载Gunicorn配置: django_path=/home/xiaji/statuspage, project_name=statuspage +2025-08-28 22:20:59.204 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:21:00.318 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:21:07.110 | ERROR | threads:run:689 - Django项目不存在: /home/xiaji/statuspage +2025-08-28 22:21:07.112 | ERROR | gunicorn_tab:on_test_gunicorn_result:367 - Gunicorn测试失败: Django项目不存在: /home/xiaji/statuspage +2025-08-28 22:24:30.595 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:24:30.635 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:24:30.636 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/statuspage +2025-08-28 22:24:30.636 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:24:30.637 | INFO | gunicorn_tab:load_gunicorn_config:175 - 从当前服务器配置加载Gunicorn配置: django_path=/home/xiaji/statuspage, project_name=statuspage +2025-08-28 22:24:30.638 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:24:32.673 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:26:19.189 | INFO | __main__::109 - 应用程序启动 +2025-08-28 22:26:19.228 | INFO | remote_command_tab:load_git_config:109 - 从配置文件加载git配置: git_url=http://192.168.3.241:3000/xiaji/webstatus, project_path=/home/xiaji/ +2025-08-28 22:26:19.229 | INFO | django_tab:load_django_path:115 - 从当前服务器配置加载django路径: /home/xiaji/statuspage +2025-08-28 22:26:19.229 | INFO | django_tab:__init__:22 - Django标签已连接到服务器切换信号 +2025-08-28 22:26:19.231 | INFO | gunicorn_tab:load_gunicorn_config:175 - 从当前服务器配置加载Gunicorn配置: django_path=/home/xiaji/statuspage, project_name=statuspage +2025-08-28 22:26:19.231 | INFO | gunicorn_tab:__init__:50 - Gunicorn标签已连接到服务器切换信号 +2025-08-28 22:26:25.092 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 22:26:31.515 | INFO | threads:run:707 - 找到wsgi.py文件: /home/xiaji/statuspage/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/handlers/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/django/core/wsgi.py +/home/xiaji/.local/lib/python3.12/site-packages/asgiref/wsgi.py +2025-08-28 22:26:36.591 | ERROR | threads:run:732 - Gunicorn测试失败 +2025-08-28 22:26:36.592 | ERROR | gunicorn_tab:on_test_gunicorn_result:367 - Gunicorn测试失败: Gunicorn测试失败 +2025-08-28 22:27:18.620 | INFO | threads:run:756 - 准备上传服务文件: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:18.634 | INFO | threads:run:763 - 临时服务文件创建成功: /tmp/gunicorn_django.service +2025-08-28 22:27:18.654 | INFO | threads:run:781 - 服务文件移动成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:18.717 | INFO | threads:run:799 - 服务文件权限设置成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:18.768 | INFO | threads:run:807 - 服务文件验证成功: -rw-r--r-- 1 xiaji xiaji 703 Aug 28 22:27 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:19.090 | INFO | threads:run:831 - systemd重新加载成功 +2025-08-28 22:27:19.712 | INFO | threads:run:839 - 服务被systemd识别: gunicorn_django.service disabled enabled +2025-08-28 22:27:19.714 | INFO | threads:run:847 - 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:19.715 | INFO | gunicorn_tab:on_upload_service_result:408 - 服务文件上传成功: 服务文件上传成功: /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:24.287 | INFO | threads:run:875 - 执行服务管理命令: systemctl restart gunicorn_django +2025-08-28 22:27:24.295 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 703 Aug 28 22:27 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:24.366 | INFO | threads:run:920 - 服务restart成功: gunicorn_django +2025-08-28 22:27:24.367 | INFO | gunicorn_tab:on_manage_service_result:456 - 服务操作成功: 服务restart成功: gunicorn_django +2025-08-28 22:27:28.045 | INFO | threads:run:875 - 执行服务管理命令: systemctl enable gunicorn_django +2025-08-28 22:27:28.054 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 703 Aug 28 22:27 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:28.368 | INFO | threads:run:920 - 服务enable成功: gunicorn_django +2025-08-28 22:27:28.371 | INFO | gunicorn_tab:on_manage_service_result:456 - 服务操作成功: 服务enable成功: gunicorn_django +2025-08-28 22:27:32.509 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 22:27:32.518 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 703 Aug 28 22:27 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:32.587 | ERROR | threads:run:907 - 服务状态查询失败: [sudo] password for xiaji: +2025-08-28 22:27:32.588 | ERROR | gunicorn_tab:on_manage_service_result:459 - 服务操作失败: [sudo] password for xiaji: +2025-08-28 22:27:52.590 | INFO | threads:run:875 - 执行服务管理命令: systemctl status gunicorn_django +2025-08-28 22:27:52.599 | INFO | threads:run:889 - 服务文件存在: -rw-r--r-- 1 xiaji xiaji 703 Aug 28 22:27 /etc/systemd/system/gunicorn_django.service +2025-08-28 22:27:52.670 | ERROR | threads:run:907 - 服务状态查询失败: [sudo] password for xiaji: +2025-08-28 22:27:52.671 | ERROR | gunicorn_tab:on_manage_service_result:459 - 服务操作失败: [sudo] password for xiaji: diff --git a/config.json b/config.json index 30ac249..6f34109 100644 --- a/config.json +++ b/config.json @@ -9,7 +9,7 @@ "project_name": "statuspage", "git_url": "http://192.168.3.241:3000/xiaji/webstatus", "remote_directory": "/home/xiaji/", - "django_path": "/home/xiaji/" + "django_path": "/home/xiaji/statuspage" }, { "alias": "生产服务器", diff --git a/django_tab.py b/django_tab.py index 60bd23d..2c1487d 100644 --- a/django_tab.py +++ b/django_tab.py @@ -1,4 +1,5 @@ import os +import json from loguru import logger from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QComboBox, QMessageBox, QTextEdit, @@ -15,6 +16,10 @@ class DjangoTab(QWidget): 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("Django标签已连接到服务器切换信号") def init_ui(self): layout = QVBoxLayout() @@ -100,9 +105,31 @@ class DjangoTab(QWidget): self.load_django_path() def load_django_path(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) + """从当前服务器配置加载Django路径""" + 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', '') + self.django_path_input.setText(django_path) + logger.info(f"从当前服务器配置加载django路径: {django_path}") + 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('django_path', '') + self.django_path_input.setText(django_path) + logger.info(f"从配置文件加载django路径: {django_path}") + except Exception as e: + logger.error(f"加载django路径失败: {str(e)}") + # 不显示警告,避免影响用户体验 + QMessageBox.warning(self, "警告", f"加载django路径失败: {str(e)}") def check_ssh_connection(self): if not self.parent or not self.parent.ssh_client: diff --git a/gunicorn_tab.py b/gunicorn_tab.py index a90423c..1cc5e6f 100644 --- a/gunicorn_tab.py +++ b/gunicorn_tab.py @@ -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") \ No newline at end of file diff --git a/main.py b/main.py index 7f5599a..b36d3a2 100644 --- a/main.py +++ b/main.py @@ -101,12 +101,7 @@ class MainWindow(QMainWindow): def on_tab_changed(self, index): """标签切换事件处理""" - tab_text = self.tab_widget.tabText(index) - if tab_text == "Gunicorn": - # 切换到Gunicorn标签时自动检测服务状态 - logger.info("切换到Gunicorn标签,自动检测服务状态") - # 延迟执行以确保UI完全加载 - QTimer.singleShot(500, self.gunicorn_tab.check_service_status) + pass if __name__ == "__main__": diff --git a/remote_command_tab.py b/remote_command_tab.py index 9aee48b..5708cf1 100644 --- a/remote_command_tab.py +++ b/remote_command_tab.py @@ -1,4 +1,5 @@ import os +import json from loguru import logger from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QComboBox, QMessageBox, QTextEdit, @@ -6,7 +7,7 @@ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineE from PySide6.QtCore import Qt from threads import (GitInstallThread, GitCloneThread, ListDirectoryThread, - DeleteDirectoryThread, SetTimezoneAndRestartThread, + SetTimezoneAndRestartThread, CheckFirewallThread, OpenPortThread) @@ -33,11 +34,6 @@ class RemoteCommandTab(QWidget): self.project_path_input.setPlaceholderText("/home/user/project") git_layout.addWidget(self.project_path_input, 1, 1) - git_layout.addWidget(QLabel("删除目录:"), 2, 0) - self.delete_dir_input = QLineEdit() - self.delete_dir_input.setPlaceholderText("/home/user/old_project") - git_layout.addWidget(self.delete_dir_input, 2, 1) - self.install_git_btn = QPushButton("安装Git") self.install_git_btn.clicked.connect(self.install_git) git_layout.addWidget(self.install_git_btn, 0, 2) @@ -50,10 +46,6 @@ class RemoteCommandTab(QWidget): self.list_dir_btn.clicked.connect(self.list_directory) git_layout.addWidget(self.list_dir_btn, 2, 2) - self.delete_dir_btn = QPushButton("删除目录") - self.delete_dir_btn.clicked.connect(self.delete_directory) - git_layout.addWidget(self.delete_dir_btn, 3, 2) - self.set_timezone_btn = QPushButton("设置时区并重启") self.set_timezone_btn.clicked.connect(self.set_timezone_and_restart) git_layout.addWidget(self.set_timezone_btn, 3, 0, 1, 2) @@ -80,17 +72,6 @@ class RemoteCommandTab(QWidget): firewall_group.setLayout(firewall_layout) layout.addWidget(firewall_group) - # Settings.py编辑器 - settings_group = QGroupBox("Settings.py编辑器") - settings_layout = QVBoxLayout() - - self.settings_editor = QTextEdit() - self.settings_editor.setPlaceholderText("settings.py内容将在这里显示...") - settings_layout.addWidget(self.settings_editor) - - settings_group.setLayout(settings_layout) - layout.addWidget(settings_group) - # 操作输出 output_group = QGroupBox("操作输出") output_layout = QVBoxLayout() @@ -106,15 +87,31 @@ class RemoteCommandTab(QWidget): layout.addStretch() self.setLayout(layout) - # 加载Git配置 + # 从配置文件加载git配置 self.load_git_config() def load_git_config(self): - if self.parent and hasattr(self.parent, 'server_connection_tab'): - git_url = self.parent.server_connection_tab.git_url_input.text() - remote_dir = self.parent.server_connection_tab.remote_dir_input.text() - self.git_url_input.setText(git_url) - self.project_path_input.setText(remote_dir) + try: + # 从config.json文件读取配置 + 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] + git_url = server_config.get('git_url', '') + project_path = server_config.get('remote_directory', '') + + self.git_url_input.setText(git_url) + self.project_path_input.setText(project_path) + + logger.info(f"从配置文件加载git配置: git_url={git_url}, project_path={project_path}") + else: + logger.warning("配置文件中未找到服务器配置") + except Exception as e: + logger.error(f"加载git配置失败: {str(e)}") + QMessageBox.warning(self, "警告", f"加载git配置失败: {str(e)}") def install_git(self): if not self.check_ssh_connection(): @@ -147,6 +144,22 @@ class RemoteCommandTab(QWidget): QMessageBox.warning(self, "警告", "请填写Git仓库URL和项目路径") return + # 从config.json获取django_path作为克隆目标路径 + try: + 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('django_path', '') + + if django_path: + project_path = django_path + logger.info(f"使用django_path作为克隆目标路径: {django_path}") + except Exception as e: + logger.error(f"获取django_path失败: {str(e)}") + self.output_text.append(f"正在克隆 {git_url} 到 {project_path}...") self.clone_btn.setEnabled(False) @@ -183,42 +196,11 @@ class RemoteCommandTab(QWidget): self.list_dir_btn.setEnabled(True) if success: self.output_text.append(f"目录列表:\n{message}") - logger.info(f"目录列表成功") + logger.info(f"目录列表成功:\n{message}") else: self.output_text.append(f"列出目录失败: {message}") logger.error(f"列出目录失败: {message}") - def delete_directory(self): - if not self.check_ssh_connection(): - return - - path = self.delete_dir_input.text().strip() - if not path: - QMessageBox.warning(self, "警告", "请输入要删除的目录路径") - return - - reply = QMessageBox.question(self, "确认删除", - f"确定要删除目录 {path} 吗?此操作不可撤销!", - QMessageBox.Yes | QMessageBox.No) - if reply == QMessageBox.No: - return - - self.output_text.append(f"正在删除目录 {path}...") - self.delete_dir_btn.setEnabled(False) - - self.delete_dir_thread = DeleteDirectoryThread(self.parent.ssh_client, path) - self.delete_dir_thread.result_ready.connect(self.on_delete_directory_result) - self.delete_dir_thread.start() - - def on_delete_directory_result(self, success, message): - self.delete_dir_btn.setEnabled(True) - if success: - self.output_text.append(f"目录删除成功: {message}") - logger.info(f"目录删除成功: {message}") - else: - self.output_text.append(f"目录删除失败: {message}") - logger.error(f"目录删除失败: {message}") - def set_timezone_and_restart(self): if not self.check_ssh_connection(): return diff --git a/server_connection_tab.py b/server_connection_tab.py index 36ab8d5..97bc6ef 100644 --- a/server_connection_tab.py +++ b/server_connection_tab.py @@ -3,13 +3,16 @@ import os from loguru import logger from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QComboBox, QMessageBox) -from PySide6.QtCore import Qt +from PySide6.QtCore import Qt, Signal # 添加Signal导入 import paramiko from threads import SSHConnectionThread class ServerConnectionTab(QWidget): + # 添加服务器切换信号 + server_changed = Signal(dict) + def __init__(self): super().__init__() self.ssh_client = None @@ -154,6 +157,9 @@ class ServerConnectionTab(QWidget): self.git_url_input.setText(server.get("git_url", "")) self.remote_dir_input.setText(server.get("remote_directory", "")) self.django_path_input.setText(server.get("django_path", "")) + + # 发送服务器切换信号 + self.server_changed.emit(server) break def save_server_config(self): @@ -222,4 +228,20 @@ class ServerConnectionTab(QWidget): else: self.status_label.setText(f"连接失败: {message}") self.status_label.setStyleSheet("color: red;") - self.ssh_client = None \ No newline at end of file + self.ssh_client = None + + def get_current_config(self): + """获取当前选中的服务器配置""" + try: + alias = self.server_combo.currentText() + if not alias: + return None + + servers = self.config.get("servers", []) + for server in servers: + if server.get("alias") == alias: + return server + return None + except Exception as e: + logger.error(f"获取当前服务器配置失败: {e}") + return None \ No newline at end of file diff --git a/threads.py b/threads.py index 7507623..7e694e0 100644 --- a/threads.py +++ b/threads.py @@ -307,7 +307,7 @@ class DjangoInstallThread(QThread): self.progress_updated.emit(30) # 尝试使用pip安装 - stdin, stdout, stderr = self.ssh_client.exec_command("pip3 install django") + stdin, stdout, stderr = self.ssh_client.exec_command("pip3 install --break-system-packages django") exit_status = stdout.channel.recv_exit_status() if exit_status == 0: @@ -372,7 +372,7 @@ class DjangoTestThread(QThread): if exit_status == 0: self.progress_updated.emit(50) # 安装依赖 - stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && pip3 install -r requirements.txt") + stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && pip3 install --break-system-packages -r requirements.txt") exit_status = stdout.channel.recv_exit_status() if exit_status != 0: @@ -384,7 +384,7 @@ class DjangoTestThread(QThread): self.progress_updated.emit(70) # 运行Django测试服务器 - stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && python3 manage.py runserver 0.0.0.0:8000 --noreload &") + stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && timeout 10 python3 manage.py runserver 0.0.0.0:8000 --noreload &") time.sleep(3) # 等待服务器启动 # 检查服务器是否运行 @@ -692,15 +692,23 @@ class GunicornTestThread(QThread): self.progress_updated.emit(30) # 检查wsgi.py文件 - project_name = os.path.basename(self.django_path) - wsgi_path = f"{self.django_path}/{project_name}/wsgi.py" + project_name = os.path.basename(self.django_path.rstrip('/')) + wsgi_path = f"{self.django_path.rstrip('/')}/{project_name}/wsgi.py" stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {wsgi_path}") exit_status = stdout.channel.recv_exit_status() if exit_status != 0: - self.result_ready.emit(False, f"wsgi.py文件不存在: {wsgi_path}") - logger.error(f"wsgi.py文件不存在: {wsgi_path}") - return + # 尝试在Django项目根目录下查找wsgi.py文件 + stdin, stdout, stderr = self.ssh_client.exec_command(f"find {self.django_path} -name wsgi.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + wsgi_path = stdout.read().decode().strip() + logger.info(f"找到wsgi.py文件: {wsgi_path}") + else: + self.result_ready.emit(False, f"wsgi.py文件不存在: {wsgi_path}") + logger.error(f"wsgi.py文件不存在: {wsgi_path}") + return self.progress_updated.emit(50) @@ -745,11 +753,15 @@ class UploadGunicornServiceThread(QThread): service_file = f"/etc/systemd/system/{self.service_name}.service" temp_file = f"/tmp/{self.service_name}.service" + logger.info(f"准备上传服务文件: {service_file}") + sftp = self.ssh_client.open_sftp() with sftp.file(temp_file, 'w') as f: f.write(self.service_content) + logger.info(f"临时服务文件创建成功: {temp_file}") + # 移动到systemd目录 if self.password: stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S mv {temp_file} {service_file}") @@ -761,11 +773,13 @@ class UploadGunicornServiceThread(QThread): if exit_status != 0: error = stderr.read().decode() - self.result_ready.emit(False, f"服务文件移动失败: {error}") logger.error(f"服务文件移动失败: {error}") + self.result_ready.emit(False, f"服务文件移动失败: {error}") sftp.close() return + logger.info(f"服务文件移动成功: {service_file}") + # 设置权限 if self.password: stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S chmod 644 {service_file}") @@ -777,8 +791,24 @@ class UploadGunicornServiceThread(QThread): if exit_status != 0: error = stderr.read().decode() - self.result_ready.emit(False, f"权限设置失败: {error}") logger.error(f"权限设置失败: {error}") + self.result_ready.emit(False, f"权限设置失败: {error}") + sftp.close() + return + + logger.info(f"服务文件权限设置成功: {service_file}") + + # 验证服务文件是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {service_file}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + file_info = stdout.read().decode().strip() + logger.info(f"服务文件验证成功: {file_info}") + else: + error = stderr.read().decode() + logger.error(f"服务文件验证失败: {error}") + self.result_ready.emit(False, f"服务文件验证失败: {error}") sftp.close() return @@ -789,6 +819,27 @@ class UploadGunicornServiceThread(QThread): stdin.flush() else: stdin, stdout, stderr = self.ssh_client.exec_command("sudo systemctl daemon-reload") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + error = stderr.read().decode() + logger.error(f"systemd重新加载失败: {error}") + self.result_ready.emit(False, f"systemd重新加载失败: {error}") + sftp.close() + return + + logger.info(f"systemd重新加载成功") + + # 验证服务是否被systemd识别 + stdin, stdout, stderr = self.ssh_client.exec_command(f"systemctl list-unit-files | grep {self.service_name}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + service_info = stdout.read().decode().strip() + logger.info(f"服务被systemd识别: {service_info}") + else: + error = stderr.read().decode() + logger.warning(f"服务未被systemd识别: {error}") sftp.close() @@ -797,8 +848,8 @@ class UploadGunicornServiceThread(QThread): except Exception as e: error_msg = str(e) - self.result_ready.emit(False, error_msg) logger.error(f"服务文件上传异常: {error_msg}") + self.result_ready.emit(False, error_msg) class ManageGunicornServiceThread(QThread): @@ -814,7 +865,28 @@ class ManageGunicornServiceThread(QThread): def run(self): try: # 构建systemd命令 - cmd = f"systemctl {self.action} {self.service_name}" + # 注意:systemd命令中不需要.service后缀 + service_name_for_systemd = self.service_name + if service_name_for_systemd.endswith('.service'): + service_name_for_systemd = service_name_for_systemd[:-8] # 移除.service后缀 + + cmd = f"systemctl {self.action} {service_name_for_systemd}" + + logger.info(f"执行服务管理命令: {cmd}") + + # 首先检查服务文件是否存在 + service_file = f"/etc/systemd/system/{self.service_name}.service" + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {service_file}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + error = stderr.read().decode() + logger.error(f"服务文件不存在: {service_file}, 错误: {error}") + self.result_ready.emit(False, f"服务文件不存在: {self.service_name}.service") + return + + file_info = stdout.read().decode().strip() + logger.info(f"服务文件存在: {file_info}") if self.action == "status": # 状态命令需要特殊处理 @@ -828,12 +900,12 @@ class ManageGunicornServiceThread(QThread): if exit_status == 0: output = stdout.read().decode() + logger.info(f"服务状态查询成功: {service_name_for_systemd}") self.result_ready.emit(True, output) - logger.info(f"服务状态查询成功: {self.service_name}") else: error = stderr.read().decode() - self.result_ready.emit(False, error) logger.error(f"服务状态查询失败: {error}") + self.result_ready.emit(False, error) else: # 其他操作(start, stop, restart, enable, disable) if self.password: @@ -845,14 +917,14 @@ class ManageGunicornServiceThread(QThread): exit_status = stdout.channel.recv_exit_status() if exit_status == 0: - self.result_ready.emit(True, f"服务{self.action}成功: {self.service_name}") - logger.info(f"服务{self.action}成功: {self.service_name}") + logger.info(f"服务{self.action}成功: {service_name_for_systemd}") + self.result_ready.emit(True, f"服务{self.action}成功: {service_name_for_systemd}") else: error = stderr.read().decode() - self.result_ready.emit(False, error) logger.error(f"服务{self.action}失败: {error}") + self.result_ready.emit(False, error) except Exception as e: error_msg = str(e) - self.result_ready.emit(False, error_msg) - logger.error(f"服务管理异常: {error_msg}") \ No newline at end of file + logger.error(f"服务管理异常: {error_msg}") + self.result_ready.emit(False, error_msg) \ No newline at end of file