From d559a85feb42efc2be59266c06dd6d7473668a7e Mon Sep 17 00:00:00 2001 From: xiaji Date: Thu, 28 Aug 2025 20:44:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=80=E5=88=9D=E4=B8=80=E4=B8=AA=E7=89=88?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E5=B7=B2=E7=BB=8F=E5=88=9D=E6=AD=A5=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=90=84=E7=A7=8D=E5=8A=9F=E8=83=BD=20=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E8=BF=9E=E6=8E=A5=20=E8=BF=9C=E7=A8=8B=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=20django=20Gunicorn=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 89 ++ __pycache__/django_tab.cpython-38.pyc | Bin 0 -> 8678 bytes __pycache__/gunicorn_tab.cpython-38.pyc | Bin 0 -> 9305 bytes __pycache__/remote_command_tab.cpython-38.pyc | Bin 0 -> 9168 bytes .../server_connection_tab.cpython-38.pyc | Bin 0 -> 6358 bytes __pycache__/threads.cpython-38.pyc | Bin 0 -> 22664 bytes app.2025-08-25_22-27-02_430599.log | 420 +++++++++ app.2025-08-26_22-27-11_970736.log | 598 ++++++++++++ app.log | 67 ++ config.json | 25 + django_tab.py | 277 ++++++ gunicorn_tab.py | 298 ++++++ main.py | 119 +++ remote_command_tab.py | 291 ++++++ requirements.txt | 3 + server_connection_tab.py | 225 +++++ settings_backup_20250827_194227.py | 113 +++ settings_backup_20250827_194650.py | 113 +++ settings_backup_20250827_200524.py | 113 +++ settings_backup_20250827_205200.py | 116 +++ settings_backup_20250827_211246.py | 116 +++ threads.py | 858 ++++++++++++++++++ 22 files changed, 3841 insertions(+) create mode 100644 README.md create mode 100644 __pycache__/django_tab.cpython-38.pyc create mode 100644 __pycache__/gunicorn_tab.cpython-38.pyc create mode 100644 __pycache__/remote_command_tab.cpython-38.pyc create mode 100644 __pycache__/server_connection_tab.cpython-38.pyc create mode 100644 __pycache__/threads.cpython-38.pyc create mode 100644 app.2025-08-25_22-27-02_430599.log create mode 100644 app.2025-08-26_22-27-11_970736.log create mode 100644 app.log create mode 100644 config.json create mode 100644 django_tab.py create mode 100644 gunicorn_tab.py create mode 100644 main.py create mode 100644 remote_command_tab.py create mode 100644 requirements.txt create mode 100644 server_connection_tab.py create mode 100644 settings_backup_20250827_194227.py create mode 100644 settings_backup_20250827_194650.py create mode 100644 settings_backup_20250827_200524.py create mode 100644 settings_backup_20250827_205200.py create mode 100644 settings_backup_20250827_211246.py create mode 100644 threads.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d26fa1 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# 服务器管理工具 + +一个基于PySide6的桌面应用程序,用于管理远程服务器连接和执行远程命令。 + +## 功能特性 + +### 服务器连接标签 +- 自动读取同目录下的config.json配置文件 +- 支持多个服务器配置的别名选择 +- 自动填充服务器信息(IP地址、端口、用户名、密码、项目名称) +- Git配置(Git仓库URL、远程目录路径) +- 支持保存和更新配置文件 +- SSH协议连接服务器并显示连接状态 + +### 远程命令标签 +- **安装Git**:检查并远程安装Git(如果未安装) +- **拉取代码**:根据提供的URL拉取代码到指定路径 +- 显示操作状态和结果 +- 实时进度显示 + +## 安装和运行 + +### 1. 安装依赖 +```bash +pip install -r requirements.txt +``` + +### 2. 配置服务器信息 +编辑`config.json`文件,添加您的服务器连接信息: +```json +{ + "servers": [ + { + "alias": "服务器别名", + "host": "服务器IP地址", + "port": 22, + "username": "用户名", + "password": "密码", + "project_name": "项目名称" + } + ] +} +``` + +### 3. 运行程序 +```bash +python main.py +``` + +## 使用说明 + +### 使用说明 + +### 服务器连接 +1. 从下拉列表选择服务器别名,程序会自动填充连接信息 +2. 填写Git配置信息(Git仓库URL、远程目录路径) +3. 点击"保存配置"按钮可以保存或更新服务器配置 +4. 点击"连接服务器"按钮建立SSH连接 +5. 连接状态会显示在界面底部 + +### 远程命令 +1. 确保已成功连接服务器 +2. **安装Git**:点击"安装Git"按钮检查并安装Git(如果未安装) +3. **拉取代码**: + - 仓库URL和项目路径会根据服务器配置自动填充 + - 如需修改,可以在"仓库URL"输入框中输入Git仓库地址 + - 在"项目路径"输入框中输入服务器上的目标路径 + - 点击"拉取代码"按钮开始拉取代码 +4. **查看目录**:点击"ls -al"按钮可以查看指定目录的详细内容 +5. 操作结果会显示在输出区域 + +## 注意事项 +- 确保服务器支持SSH连接 +- 确保提供的用户名和密码正确 +- 确保服务器有足够的权限安装软件和创建目录 +- 程序会自动检测并安装Git(如果未安装) + +## 技术栈 +- **GUI框架**: PySide6 +- **SSH连接**: paramiko +- **日志记录**: loguru +- **目标服务器**: Ubuntu Linux + +## 界面预览 +程序采用现代化的界面设计,包含:\- 美观的标签页布局 +- 直观的表单输入 +- 实时状态反馈 +- 进度条显示 +- 彩色状态指示 \ No newline at end of file diff --git a/__pycache__/django_tab.cpython-38.pyc b/__pycache__/django_tab.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d59d2e6b911d208bba5d88a47cd867e5284756b2 GIT binary patch literal 8678 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 SOl&Q_15)z%;YeB=*8dMhcD}~| literal 0 HcmV?d00001 diff --git a/__pycache__/remote_command_tab.cpython-38.pyc b/__pycache__/remote_command_tab.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7082b5bab81a8799c76399d188ef78f3fa5801eb GIT binary patch literal 9168 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 c@=4-t?dVsf48Bgh($ literal 0 HcmV?d00001 diff --git a/__pycache__/server_connection_tab.cpython-38.pyc b/__pycache__/server_connection_tab.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..813705a675ea966ea79f0307711226029a320a83 GIT binary patch literal 6358 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 fa_e*JavPCu%:445 - 应用程序启动 +2025-08-25 22:27:24.671 | INFO | __main__:save_config:108 - 配置文件保存成功 +2025-08-25 22:27:34.200 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-25 22:27:34.330 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-25 22:29:21.628 | INFO | __main__::516 - 应用程序启动 +2025-08-25 22:29:48.273 | INFO | __main__::516 - 应用程序启动 +2025-08-25 22:30:19.896 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-25 22:30:19.993 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-25 22:30:21.941 | INFO | __main__:run:47 - 开始检查并安装Git +2025-08-25 22:30:21.961 | INFO | __main__:run:54 - Git已安装 +2025-08-25 22:30:21.962 | INFO | __main__:on_git_install_result:419 - Git安装结果: True - Git已安装 +2025-08-26 21:08:59.421 | INFO | __main__::516 - 应用程序启动 +2025-08-26 21:09:01.527 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:09:01.694 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-26 21:09:03.832 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:09:03.913 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-26 21:10:46.707 | INFO | __main__:run:47 - 开始检查并安装Git +2025-08-26 21:10:46.738 | INFO | __main__:on_git_install_result:419 - Git安装结果: True - Git已安装 +2025-08-26 21:10:46.739 | INFO | __main__:run:54 - Git已安装 +2025-08-26 21:10:49.648 | INFO | __main__:run:87 - 开始拉取代码: http://192.168.3.241:3000/xiaji/webstatus +2025-08-26 21:10:49.704 | INFO | __main__:run:101 - 开始克隆代码到: /home/xiaji +2025-08-26 21:10:49.757 | ERROR | __main__:run:106 - 代码拉取失败: fatal: destination path '.' already exists and is not an empty directory. + +2025-08-26 21:10:49.759 | INFO | __main__:on_git_clone_result:432 - 代码拉取结果: False - 代码拉取失败: fatal: destination path '.' already exists and is not an empty directory. + +2025-08-26 21:13:07.493 | INFO | __main__::528 - 应用程序启动 +2025-08-26 21:15:54.714 | INFO | __main__::578 - 应用程序启动 +2025-08-26 21:15:54.749 | INFO | __main__:load_git_config:491 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:15:58.440 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:15:58.536 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-26 21:16:14.794 | INFO | __main__:run:87 - 开始拉取代码: https://github.com/example/statuspage.git +2025-08-26 21:16:14.859 | INFO | __main__:run:105 - 目录 /home/xiaji/ 不为空,正在清空目录 +2025-08-26 21:16:14.913 | INFO | __main__:run:113 - 开始克隆代码到: /home/xiaji/ +2025-08-26 21:18:30.048 | ERROR | __main__:run:118 - 代码拉取失败: Cloning into '.'... +fatal: unable to access 'https://github.com/example/statuspage.git/': Failed to connect to github.com port 443 after 135044 ms: Could not connect to server + +2025-08-26 21:18:30.053 | INFO | __main__:on_git_clone_result:469 - 代码拉取结果: False - 代码拉取失败: Cloning into '.'... +fatal: unable to access 'https://github.com/example/statuspage.git/': Failed to connect to github.com port 443 after 135044 ms: Could not connect to server + +2025-08-26 21:18:54.240 | INFO | __main__:save_config:153 - 配置文件保存成功 +2025-08-26 21:18:57.954 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:18:58.042 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-26 21:19:04.769 | INFO | __main__:run:87 - 开始拉取代码: http://192.168.3.241:3000/xiaji/webstatus +2025-08-26 21:19:04.834 | INFO | __main__:run:105 - 目录 /home/xiaji/ 不为空,正在清空目录 +2025-08-26 21:19:04.884 | INFO | __main__:run:113 - 开始克隆代码到: /home/xiaji/ +2025-08-26 21:19:04.979 | INFO | __main__:run:123 - 代码拉取成功到: /home/xiaji/ +2025-08-26 21:19:04.981 | INFO | __main__:on_git_clone_result:469 - 代码拉取结果: True - 代码拉取成功到: /home/xiaji/ +2025-08-26 21:21:31.689 | INFO | __main__::651 - 应用程序启动 +2025-08-26 21:21:31.725 | INFO | __main__:load_git_config:528 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:21:41.068 | INFO | __main__:run:25 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:21:41.156 | INFO | __main__:run:31 - 服务器连接成功 +2025-08-26 21:21:43.287 | INFO | __main__:run:141 - 开始列出目录内容: /home/xiaji/ +2025-08-26 21:21:43.298 | INFO | __main__:run:155 - 成功列出目录内容: /home/xiaji/ +2025-08-26 21:21:43.303 | INFO | __main__:on_list_directory_result:567 - 目录列表结果: True - 目录内容: +total 168 +drwxr-x--- 7 xiaji xiaji 4096 Aug 26 13:21 . +drwxr-xr-x 3 root root 4096 Aug 26 2025 .. +drwx------ 2 xiaji xiaji 4096 Aug 26 13:21 .cache +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 13:19 db.sqlite3 +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 13:19 .git +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 13:19 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 13:19 requirements.txt +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 13:19 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 13:19 statuspage +drwxrwxr-x 2 xiaji xiaji 4096 Aug 26 13:19 部署文件夹 + +2025-08-26 21:37:21.441 | INFO | __main__::1164 - 应用程序启动 +2025-08-26 21:37:21.476 | INFO | __main__:load_git_config:761 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:37:21.478 | INFO | __main__:load_django_config:1073 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:37:34.833 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:37:34.920 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:37:52.993 | INFO | __main__:save_config:408 - 配置文件保存成功 +2025-08-26 21:38:01.208 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:38:01.227 | ERROR | __main__:run:180 - Django安装失败: 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-26 21:38:01.232 | INFO | __main__:on_django_install_result:990 - Django安装结果: False - Django安装失败: 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-26 21:42:19.122 | INFO | __main__::1186 - 应用程序启动 +2025-08-26 21:42:19.156 | INFO | __main__:load_git_config:783 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:42:19.157 | INFO | __main__:load_django_config:1095 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:42:21.426 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:42:21.525 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:42:24.983 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:42:24.993 | ERROR | __main__:run:216 - Django安装失败: bash: line 1: pip3: command not found + +2025-08-26 21:42:24.997 | INFO | __main__:on_django_install_result:1012 - Django安装结果: False - Django安装失败: bash: line 1: pip3: command not found + +2025-08-26 21:43:24.841 | INFO | __main__::1186 - 应用程序启动 +2025-08-26 21:43:24.879 | INFO | __main__:load_git_config:783 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:43:24.881 | INFO | __main__:load_django_config:1095 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:43:26.831 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:43:26.918 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:43:30.104 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:43:30.112 | ERROR | __main__:run:216 - Django安装失败: bash: line 1: pip: command not found + +2025-08-26 21:43:30.115 | INFO | __main__:on_django_install_result:1012 - Django安装结果: False - Django安装失败: bash: line 1: pip: command not found + +2025-08-26 21:44:17.866 | INFO | __main__::1186 - 应用程序启动 +2025-08-26 21:44:17.900 | INFO | __main__:load_git_config:783 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:44:17.901 | INFO | __main__:load_django_config:1095 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:44:19.443 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:44:19.531 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:44:21.222 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:44:21.248 | ERROR | __main__:run:216 - Django安装失败: /usr/bin/python3: No module named pip + +2025-08-26 21:44:21.251 | INFO | __main__:on_django_install_result:1012 - Django安装结果: False - Django安装失败: /usr/bin/python3: No module named pip + +2025-08-26 21:45:20.140 | INFO | __main__::1199 - 应用程序启动 +2025-08-26 21:45:20.183 | INFO | __main__:load_git_config:796 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:45:20.184 | INFO | __main__:load_django_config:1108 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:45:22.205 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:45:22.291 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:45:24.147 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:45:24.171 | INFO | __main__:run:178 - pip未安装,正在安装pip... +2025-08-26 21:45:26.500 | ERROR | __main__:run:184 - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:45:26.508 | INFO | __main__:on_django_install_result:1025 - Django安装结果: False - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:45:52.074 | INFO | __main__::1204 - 应用程序启动 +2025-08-26 21:45:52.110 | INFO | __main__:load_git_config:801 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:45:52.111 | INFO | __main__:load_django_config:1113 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:45:53.783 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:45:53.874 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:45:55.539 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:45:55.564 | INFO | __main__:run:178 - pip未安装,正在安装pip... +2025-08-26 21:45:55.629 | INFO | __main__:run:183 - ensurepip失败,尝试使用apt-get安装pip... +2025-08-26 21:45:57.544 | ERROR | __main__:run:189 - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:45:57.547 | INFO | __main__:on_django_install_result:1030 - Django安装结果: False - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:46:48.146 | INFO | __main__::1223 - 应用程序启动 +2025-08-26 21:46:48.178 | INFO | __main__:load_git_config:820 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:46:48.179 | INFO | __main__:load_django_config:1132 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:46:54.255 | INFO | __main__:run:26 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:46:54.346 | INFO | __main__:run:32 - 服务器连接成功 +2025-08-26 21:46:56.973 | INFO | __main__:run:173 - 开始安装Django +2025-08-26 21:46:56.997 | INFO | __main__:run:178 - pip未安装,正在安装pip... +2025-08-26 21:46:57.063 | INFO | __main__:run:183 - ensurepip失败,尝试使用get-pip.py脚本安装pip... +2025-08-26 21:47:10.268 | INFO | __main__:run:192 - get-pip.py失败,尝试使用apt-get安装pip... +2025-08-26 21:47:12.149 | ERROR | __main__:run:198 - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:47:12.159 | INFO | __main__:on_django_install_result:1049 - Django安装结果: False - pip安装失败: [sudo] password for xiaji: Sorry, try again. +[sudo] password for xiaji: +sudo: no password was provided +sudo: 1 incorrect password attempt + +2025-08-26 21:52:21.927 | INFO | __main__::1296 - 应用程序启动 +2025-08-26 21:52:21.959 | INFO | __main__:load_git_config:893 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:52:21.960 | INFO | __main__:load_django_config:1205 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:52:23.682 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:52:23.773 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 21:52:26.898 | INFO | __main__:run:228 - 开始安装Django +2025-08-26 21:52:26.926 | INFO | __main__:run:233 - pip未安装,正在安装pip... +2025-08-26 21:52:26.995 | INFO | __main__:run:238 - ensurepip失败,尝试使用get-pip.py脚本安装pip... +2025-08-26 21:52:30.360 | INFO | __main__:run:247 - get-pip.py失败,尝试使用apt-get安装pip... +2025-08-26 21:53:57.244 | INFO | __main__::1320 - 应用程序启动 +2025-08-26 21:53:57.276 | INFO | __main__:load_git_config:905 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:53:57.276 | INFO | __main__:load_django_config:1229 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:54:04.423 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:54:04.511 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 21:54:07.059 | INFO | __main__:run:240 - 开始安装Django +2025-08-26 21:54:07.085 | INFO | __main__:run:245 - pip未安装,正在安装pip... +2025-08-26 21:54:07.150 | INFO | __main__:run:250 - ensurepip失败,尝试使用get-pip.py脚本安装pip... +2025-08-26 21:54:09.934 | INFO | __main__:run:259 - get-pip.py失败,尝试使用apt-get安装pip... +2025-08-26 21:54:14.798 | INFO | __main__:set_password:236 - 密码已设置 +2025-08-26 21:54:14.798 | INFO | __main__:on_request_password:1035 - 用户通过对话框输入了sudo密码 +2025-08-26 21:54:14.860 | INFO | __main__:get_sudo_password:229 - 密码输入流程完成 +2025-08-26 21:54:36.123 | INFO | __main__:run:289 - pip安装成功 +2025-08-26 21:54:36.524 | ERROR | __main__:run:338 - 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-26 21:54:36.532 | INFO | __main__:on_django_install_result:1146 - Django安装结果: False - 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-26 21:56:23.641 | INFO | __main__::1320 - 应用程序启动 +2025-08-26 21:56:23.679 | INFO | __main__:load_git_config:905 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 21:56:23.680 | INFO | __main__:load_django_config:1229 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 21:56:25.450 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 21:56:25.537 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 21:56:28.466 | INFO | __main__:run:240 - 开始安装Django +2025-08-26 22:00:18.695 | INFO | __main__:run:305 - Django安装成功,版本: 5.2.5 +2025-08-26 22:00:18.699 | INFO | __main__:on_django_install_result:1146 - Django安装结果: True - Django安装成功,版本: 5.2.5 +2025-08-26 22:00:26.706 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:00:26.764 | ERROR | __main__:run:371 - settings.py文件不存在: /home/xiaji//settings.py +2025-08-26 22:00:26.765 | INFO | __main__:on_django_test_result:1159 - Django测试结果: False - settings.py文件不存在: /home/xiaji//settings.py +2025-08-26 22:04:00.950 | INFO | __main__::1337 - 应用程序启动 +2025-08-26 22:04:00.984 | INFO | __main__:load_git_config:922 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:04:00.985 | INFO | __main__:load_django_config:1246 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:04:02.656 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:04:02.746 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:04:06.330 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:04:06.330 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:04:06.376 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +./部署文件夹/settings.py +2025-08-26 22:04:06.376 | INFO | __main__:run:367 - 项目目录: ./statuspage/settings.py +./部署文件夹 +2025-08-26 22:04:06.427 | ERROR | __main__:run:374 - manage.py文件不存在: ./statuspage/settings.py +./部署文件夹/manage.py +2025-08-26 22:04:06.432 | INFO | __main__:on_django_test_result:1176 - Django测试结果: False - manage.py文件不存在: ./statuspage/settings.py +./部署文件夹/manage.py +2025-08-26 22:10:50.613 | INFO | __main__::1411 - 应用程序启动 +2025-08-26 22:10:50.651 | INFO | __main__:load_git_config:961 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:10:50.652 | INFO | __main__:load_django_config:1320 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:10:51.993 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:10:52.100 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:10:58.822 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:10:58.822 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:10:58.865 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +./部署文件夹/settings.py +2025-08-26 22:10:58.865 | INFO | __main__:run:367 - 项目目录: ./statuspage/settings.py +./部署文件夹 +2025-08-26 22:10:58.918 | ERROR | __main__:run:374 - manage.py文件不存在: ./statuspage/settings.py +./部署文件夹/manage.py +2025-08-26 22:10:58.923 | INFO | __main__:on_django_test_result:1250 - Django测试结果: False - manage.py文件不存在: ./statuspage/settings.py +./部署文件夹/manage.py +2025-08-26 22:11:11.658 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-26 22:11:11.669 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-26 22:11:11.672 | INFO | __main__:on_list_directory_result:1000 - 目录列表结果: True - 目录内容: +total 2272 +drwxr-x--- 8 xiaji xiaji 4096 Aug 26 14:00 . +drwxr-xr-x 3 root root 4096 Aug 26 2025 .. +drwx------ 3 xiaji xiaji 4096 Aug 26 13:56 .cache +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 13:19 db.sqlite3 +-rw-rw-r-- 1 xiaji xiaji 2148718 Aug 26 13:54 get-pip.py +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 13:19 .git +drwxrwxr-x 4 xiaji xiaji 4096 Aug 26 14:00 .local +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 13:19 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 13:19 requirements.txt +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 13:19 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 13:19 statuspage +-rw-r--r-- 1 xiaji xiaji 0 Aug 26 13:54 .sudo_as_admin_successful +drwxrwxr-x 2 xiaji xiaji 4096 Aug 26 13:19 部署文件夹 + +2025-08-26 22:17:30.337 | INFO | __main__::1499 - 应用程序启动 +2025-08-26 22:17:30.371 | INFO | __main__:load_git_config:1006 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:17:30.373 | INFO | __main__:load_django_config:1408 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:17:32.077 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:17:32.167 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:17:38.407 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-26 22:17:38.416 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-26 22:17:38.420 | INFO | __main__:on_list_directory_result:1045 - 目录列表结果: True - 目录内容: +total 2272 +drwxr-x--- 8 xiaji xiaji 4096 Aug 26 14:00 . +drwxr-xr-x 3 root root 4096 Aug 26 2025 .. +drwx------ 3 xiaji xiaji 4096 Aug 26 13:56 .cache +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 13:19 db.sqlite3 +-rw-rw-r-- 1 xiaji xiaji 2148718 Aug 26 13:54 get-pip.py +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 13:19 .git +drwxrwxr-x 4 xiaji xiaji 4096 Aug 26 14:00 .local +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 13:19 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 13:19 requirements.txt +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 13:19 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 13:19 statuspage +-rw-r--r-- 1 xiaji xiaji 0 Aug 26 13:54 .sudo_as_admin_successful +drwxrwxr-x 2 xiaji xiaji 4096 Aug 26 13:19 部署文件夹 + +2025-08-26 22:17:43.607 | INFO | __main__:run:596 - 开始删除目录: /home/xiaji/ +2025-08-26 22:17:43.792 | ERROR | __main__:run:618 - 删除目录失败: rm: cannot remove '/home/xiaji/': Permission denied +2025-08-26 22:17:43.794 | INFO | __main__:on_delete_directory_result:1088 - 删除目录结果: False - 删除目录失败: rm: cannot remove '/home/xiaji/': Permission denied +2025-08-26 22:18:25.763 | INFO | __main__::1507 - 应用程序启动 +2025-08-26 22:18:25.800 | INFO | __main__:load_git_config:1014 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:18:25.801 | INFO | __main__:load_django_config:1416 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:18:27.004 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:18:27.089 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:18:31.163 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-26 22:18:31.171 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-26 22:18:31.174 | INFO | __main__:on_list_directory_result:1053 - 目录列表结果: True - 目录内容: +total 12 +drwxr-x--- 3 xiaji xiaji 4096 Aug 26 14:18 . +drwxr-xr-x 3 root root 4096 Aug 26 2025 .. +drwx------ 2 xiaji xiaji 4096 Aug 26 14:18 .cache + +2025-08-26 22:18:36.660 | INFO | __main__:run:129 - 开始拉取代码: http://192.168.3.241:3000/xiaji/webstatus +2025-08-26 22:18:36.731 | INFO | __main__:run:147 - 目录 /home/xiaji/ 不为空,正在清空目录 +2025-08-26 22:18:36.744 | INFO | __main__:run:155 - 开始克隆代码到: /home/xiaji/ +2025-08-26 22:18:36.842 | INFO | __main__:run:165 - 代码拉取成功到: /home/xiaji/ +2025-08-26 22:18:36.843 | INFO | __main__:on_git_clone_result:992 - 代码拉取结果: True - 代码拉取成功到: /home/xiaji/ +2025-08-26 22:18:37.904 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-26 22:18:37.912 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-26 22:18:37.914 | INFO | __main__:on_list_directory_result:1053 - 目录列表结果: True - 目录内容: +total 160 +drwxr-x--- 5 xiaji xiaji 4096 Aug 26 14:18 . +drwxr-xr-x 3 root root 4096 Aug 26 2025 .. +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 14:18 db.sqlite3 +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 14:18 .git +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 14:18 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 14:18 requirements.txt +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 14:18 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 14:18 statuspage + +2025-08-26 22:18:43.768 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:18:43.768 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:18:43.779 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +2025-08-26 22:18:43.779 | INFO | __main__:run:367 - 项目目录: ./statuspage +2025-08-26 22:18:43.828 | ERROR | __main__:run:374 - manage.py文件不存在: ./statuspage/manage.py +2025-08-26 22:18:43.828 | INFO | __main__:on_django_test_result:1346 - Django测试结果: False - manage.py文件不存在: ./statuspage/manage.py +2025-08-26 22:20:44.569 | INFO | __main__::1508 - 应用程序启动 +2025-08-26 22:20:44.604 | INFO | __main__:load_git_config:1015 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:20:44.605 | INFO | __main__:load_django_config:1417 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:20:45.954 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:20:46.049 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:20:48.938 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:20:48.938 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:20:48.947 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +2025-08-26 22:20:48.948 | INFO | __main__:run:367 - 项目目录: ./statuspage +2025-08-26 22:20:49.189 | ERROR | __main__:run:409 - Django服务器启动失败: Traceback (most recent call last): + File "/home/xiaji/manage.py", line 11, in main + from django.core.management import execute_from_command_line +ModuleNotFoundError: No module named 'django' + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/xiaji/manage.py", line 22, in + main() + File "/home/xiaji/manage.py", line 13, in main + raise ImportError( +ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment? + +2025-08-26 22:20:49.197 | INFO | __main__:on_django_test_result:1347 - Django测试结果: False - Django服务器启动失败: Traceback (most recent call last): + File "/home/xiaji/manage.py", line 11, in main + from django.core.management import execute_from_command_line +ModuleNotFoundError: No module named 'django' + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/xiaji/manage.py", line 22, in + main() + File "/home/xiaji/manage.py", line 13, in main + raise ImportError( +ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment? + +2025-08-26 22:21:07.760 | INFO | __main__:run:240 - 开始安装Django +2025-08-26 22:23:28.257 | INFO | __main__::1523 - 应用程序启动 +2025-08-26 22:23:28.295 | INFO | __main__:load_git_config:1033 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:23:28.297 | INFO | __main__:load_django_config:1432 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:23:30.498 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:23:30.588 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:23:46.323 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:23:46.324 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:23:46.332 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +2025-08-26 22:23:46.332 | INFO | __main__:run:367 - 项目目录: ./statuspage +2025-08-26 22:23:46.385 | INFO | __main__:run:392 - 检查Django安装状态... +2025-08-26 22:23:46.789 | ERROR | __main__:run:397 - Django未安装,请先安装Django再进行服务器测试 +2025-08-26 22:23:46.795 | INFO | __main__:on_django_test_result:1362 - Django测试结果: False - Django未安装,请先安装Django再进行服务器测试 +2025-08-26 22:23:48.755 | INFO | __main__:run:240 - 开始安装Django +2025-08-26 22:25:16.428 | INFO | __main__:run:305 - Django安装成功,版本: 5.2.5 +2025-08-26 22:25:16.429 | INFO | __main__:on_django_install_result:1349 - Django安装结果: True - Django安装成功,版本: 5.2.5 +2025-08-26 22:25:29.453 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-26 22:25:29.454 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-26 22:25:29.492 | INFO | __main__:run:366 - 找到settings.py文件: ./statuspage/settings.py +2025-08-26 22:25:29.493 | INFO | __main__:run:367 - 项目目录: ./statuspage +2025-08-26 22:25:29.544 | INFO | __main__:run:392 - 检查Django安装状态... +2025-08-26 22:25:40.055 | INFO | __main__:run:409 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-26 22:25:40.056 | INFO | __main__:on_django_test_result:1362 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-26 22:26:04.003 | INFO | __main__:run:436 - 开始下载settings.py文件: /home/xiaji//settings.py +2025-08-26 22:26:04.011 | ERROR | __main__:run:443 - settings.py文件不存在: /home/xiaji//settings.py +2025-08-26 22:26:04.012 | INFO | __main__:on_download_settings_result:1387 - 下载settings.py结果: False - settings.py文件不存在: /home/xiaji//settings.py +2025-08-26 22:26:48.391 | INFO | __main__::1527 - 应用程序启动 +2025-08-26 22:26:48.431 | INFO | __main__:load_git_config:1037 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:26:48.432 | INFO | __main__:load_django_config:1436 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:26:50.521 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:26:50.608 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:26:53.437 | INFO | __main__:run:440 - 开始下载settings.py文件: /home/xiaji/settings.py +2025-08-26 22:26:53.446 | ERROR | __main__:run:447 - settings.py文件不存在: /home/xiaji/settings.py +2025-08-26 22:26:53.451 | INFO | __main__:on_download_settings_result:1391 - 下载settings.py结果: False - settings.py文件不存在: /home/xiaji/settings.py diff --git a/app.2025-08-26_22-27-11_970736.log b/app.2025-08-26_22-27-11_970736.log new file mode 100644 index 0000000..da3a761 --- /dev/null +++ b/app.2025-08-26_22-27-11_970736.log @@ -0,0 +1,598 @@ +2025-08-26 22:27:11.967 | INFO | __main__::1531 - 应用程序启动 +2025-08-26 22:27:12.005 | INFO | __main__:load_git_config:1041 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-26 22:27:12.006 | INFO | __main__:load_django_config:1440 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-26 22:27:13.724 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-26 22:27:13.812 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-26 22:27:15.586 | INFO | __main__:run:440 - 开始下载settings.py文件: /home/xiaji/settings.py +2025-08-26 22:27:15.600 | ERROR | __main__:run:447 - settings.py文件不存在: /home/xiaji/settings.py +2025-08-26 22:27:15.603 | INFO | __main__:on_download_settings_result:1395 - 下载settings.py结果: False - settings.py文件不存在: /home/xiaji/settings.py +2025-08-27 19:34:48.208 | INFO | __main__::1533 - 应用程序启动 +2025-08-27 19:34:48.252 | INFO | __main__:load_git_config:1043 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 19:34:48.253 | INFO | __main__:load_django_config:1442 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 19:34:51.243 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 19:34:51.354 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 19:34:57.489 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-27 19:34:57.498 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-27 19:34:57.506 | INFO | __main__:on_list_directory_result:1082 - 目录列表结果: True - 目录内容: +total 168 +drwxr-x--- 7 xiaji xiaji 4096 Aug 26 14:25 . +drwxr-xr-x 3 root root 4096 Aug 26 20:10 .. +drwx------ 3 xiaji xiaji 4096 Aug 26 14:21 .cache +-rw-rw-r-- 1 xiaji xiaji 135168 Aug 26 14:18 db.sqlite3 +drwxrwxr-x 8 xiaji xiaji 4096 Aug 26 14:18 .git +drwxrwxr-x 4 xiaji xiaji 4096 Aug 26 14:25 .local +-rw-rw-r-- 1 xiaji xiaji 666 Aug 26 14:18 manage.py +-rw-rw-r-- 1 xiaji xiaji 13 Aug 26 14:18 requirements.txt +drwxrwxr-x 5 xiaji xiaji 4096 Aug 26 14:18 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 14:18 statuspage + +2025-08-27 19:35:04.761 | INFO | __main__:run:356 - 开始测试Django项目启动: /home/xiaji/ +2025-08-27 19:35:04.762 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-27 19:35:04.808 | INFO | __main__:run:368 - 找到settings.py文件: ./statuspage/settings.py +2025-08-27 19:35:04.809 | INFO | __main__:run:369 - 项目目录: ./statuspage +2025-08-27 19:35:04.858 | INFO | __main__:run:394 - 检查Django安装状态... +2025-08-27 19:35:14.808 | INFO | __main__:run:442 - 开始下载settings.py文件: /home/xiaji/settings.py +2025-08-27 19:35:14.817 | ERROR | __main__:run:449 - settings.py文件不存在: /home/xiaji/settings.py +2025-08-27 19:35:14.820 | INFO | __main__:on_download_settings_result:1397 - 下载settings.py结果: False - settings.py文件不存在: /home/xiaji/settings.py +2025-08-27 19:35:15.377 | INFO | __main__:run:411 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 19:35:15.378 | INFO | __main__:on_django_test_result:1372 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 19:35:19.455 | INFO | __main__:run:442 - 开始下载settings.py文件: /home/xiaji/settings.py +2025-08-27 19:35:19.462 | ERROR | __main__:run:449 - settings.py文件不存在: /home/xiaji/settings.py +2025-08-27 19:35:19.463 | INFO | __main__:on_download_settings_result:1397 - 下载settings.py结果: False - settings.py文件不存在: /home/xiaji/settings.py +2025-08-27 19:42:20.823 | INFO | __main__::1583 - 应用程序启动 +2025-08-27 19:42:20.864 | INFO | __main__:load_git_config:1043 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 19:42:20.865 | INFO | __main__:load_django_config:1492 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 19:42:22.887 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 19:42:22.976 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 19:42:27.102 | INFO | __main__:find_and_remember_settings_path:1459 - 正在查找settings.py文件位置... +2025-08-27 19:42:27.146 | INFO | __main__:find_and_remember_settings_path:1467 - 找到并记住settings.py文件: ./statuspage/settings.py +2025-08-27 19:42:27.367 | INFO | __main__:run:442 - 开始下载settings.py文件: ./statuspage/settings.py +2025-08-27 19:42:27.424 | INFO | __main__:run:465 - settings.py文件下载成功 +2025-08-27 19:42:27.431 | INFO | __main__:on_download_settings_result:1413 - settings.py已保存到本地: settings_backup_20250827_194227.py +2025-08-27 19:42:27.431 | INFO | __main__:on_download_settings_result:1421 - 下载settings.py结果: True - settings.py文件下载成功 +2025-08-27 19:46:43.686 | INFO | __main__::1598 - 应用程序启动 +2025-08-27 19:46:43.723 | INFO | __main__:load_git_config:1049 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 19:46:43.724 | INFO | __main__:load_django_config:1507 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 19:46:45.459 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 19:46:45.548 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 19:46:50.814 | INFO | __main__:find_and_remember_settings_path:1474 - 正在查找settings.py文件位置... +2025-08-27 19:46:50.862 | INFO | __main__:find_and_remember_settings_path:1482 - 找到并记住settings.py文件: ./statuspage/settings.py +2025-08-27 19:46:50.864 | INFO | __main__:run:442 - 开始下载settings.py文件: ./statuspage/settings.py +2025-08-27 19:46:50.961 | INFO | __main__:run:465 - settings.py文件下载成功 +2025-08-27 19:46:50.971 | INFO | __main__:on_download_settings_result:1428 - settings.py已保存到本地: settings_backup_20250827_194650.py +2025-08-27 19:46:50.971 | INFO | __main__:on_download_settings_result:1436 - 下载settings.py结果: True - settings.py文件下载成功 +2025-08-27 19:55:17.865 | INFO | __main__::1695 - 应用程序启动 +2025-08-27 19:55:17.899 | INFO | __main__:load_git_config:1106 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 19:55:17.900 | INFO | __main__:load_django_config:1604 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 19:55:19.882 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 19:55:20.010 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 19:55:26.008 | INFO | __main__:run:664 - 开始设置时区为北京时区并重启服务器 +2025-08-27 19:55:26.008 | INFO | __main__:run:667 - 设置时区为Asia/Shanghai... +2025-08-27 19:55:26.020 | ERROR | __main__:run:673 - 设置时区失败: 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-27 19:55:29.082 | INFO | __main__:on_set_timezone_and_restart_result:1214 - 设置时区和重启服务器结果: False - 设置时区失败: 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-27 20:02:54.904 | INFO | __main__::1728 - 应用程序启动 +2025-08-27 20:02:54.944 | INFO | __main__:load_git_config:1119 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 20:02:54.945 | INFO | __main__:load_django_config:1637 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 20:02:57.393 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:02:57.491 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 20:02:57.655 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:02:57.751 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 20:03:03.524 | INFO | __main__:run:670 - 开始设置时区为北京时区并重启服务器 +2025-08-27 20:03:07.898 | INFO | __main__:show_password_dialog:1221 - 用户已输入sudo密码 +2025-08-27 20:03:07.957 | INFO | __main__:run:680 - 设置时区为Asia/Shanghai... +2025-08-27 20:03:08.099 | INFO | __main__:run:693 - 当前时区: Asia/Shanghai +2025-08-27 20:03:08.099 | INFO | __main__:run:701 - 开始重启服务器... +2025-08-27 20:03:08.172 | INFO | __main__:run:712 - 时区已设置为北京时区,服务器正在重启中... +2025-08-27 20:03:10.310 | INFO | __main__:on_set_timezone_and_restart_result:1247 - 设置时区和重启服务器结果: True - 时区已设置为北京时区,服务器正在重启中... +2025-08-27 20:03:16.568 | INFO | __main__:run:67 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:03:17.861 | INFO | __main__:run:73 - 服务器连接成功 +2025-08-27 20:03:24.114 | INFO | __main__:run:183 - 开始列出目录内容: /home/xiaji/ +2025-08-27 20:03:24.125 | INFO | __main__:run:197 - 成功列出目录内容: /home/xiaji/ +2025-08-27 20:03:24.128 | INFO | __main__:on_list_directory_result:1158 - 目录列表结果: True - 目录内容: +total 168 +drwxr-x--- 7 xiaji xiaji 4096 Aug 27 20:03 . +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 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 5 xiaji xiaji 4096 Aug 26 22:18 status +drwxrwxr-x 3 xiaji xiaji 4096 Aug 26 22:18 statuspage +-rw-r--r-- 1 xiaji xiaji 0 Aug 27 20:03 .sudo_as_admin_successful + +2025-08-27 20:05:23.729 | INFO | __main__:find_and_remember_settings_path:1604 - 正在查找settings.py文件位置... +2025-08-27 20:05:23.974 | INFO | __main__:find_and_remember_settings_path:1612 - 找到并记住settings.py文件: ./statuspage/settings.py +2025-08-27 20:05:23.979 | INFO | __main__:run:442 - 开始下载settings.py文件: ./statuspage/settings.py +2025-08-27 20:05:24.077 | INFO | __main__:run:465 - settings.py文件下载成功 +2025-08-27 20:05:24.084 | INFO | __main__:on_download_settings_result:1558 - settings.py已保存到本地: settings_backup_20250827_200524.py +2025-08-27 20:05:24.084 | INFO | __main__:on_download_settings_result:1566 - 下载settings.py结果: True - settings.py文件下载成功 +2025-08-27 20:31:46.189 | INFO | __main__:run:488 - 开始上传settings.py文件: ./statuspage/settings.py +2025-08-27 20:31:46.218 | INFO | __main__:run:515 - settings.py文件上传成功,原文件已备份到: ./statuspage/settings_backup_20250827_203146.py +2025-08-27 20:31:46.219 | INFO | __main__:on_upload_settings_result:1579 - 上传settings.py结果: True - settings.py文件上传成功,原文件已备份到: ./statuspage/settings_backup_20250827_203146.py +2025-08-27 20:31:49.592 | INFO | __main__:run:356 - 开始测试Django项目启动: ./statuspage +2025-08-27 20:31:49.593 | INFO | __main__:run:359 - 正在查找settings.py文件位置... +2025-08-27 20:31:49.643 | INFO | __main__:run:368 - 找到settings.py文件: ./statuspage/settings.py +2025-08-27 20:31:49.644 | INFO | __main__:run:369 - 项目目录: ./statuspage +2025-08-27 20:31:49.693 | INFO | __main__:run:394 - 检查Django安装状态... +2025-08-27 20:32:00.301 | INFO | __main__:run:411 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:32:00.302 | INFO | __main__:on_django_test_result:1537 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:40:39.405 | INFO | __main__::1956 - 应用程序启动 +2025-08-27 20:40:39.451 | INFO | __main__:load_git_config:1243 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 20:40:39.452 | INFO | __main__:load_django_config:1865 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 20:40:41.463 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:40:41.555 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 20:40:46.641 | INFO | __main__:run:730 - 开始检查防火墙状态 +2025-08-27 20:40:46.664 | INFO | __main__:on_check_firewall_result:1459 - 检查防火墙结果: False - 检查防火墙状态失败: 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-27 20:40:46.665 | ERROR | __main__:run:750 - 检查防火墙状态失败: 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-27 20:44:01.496 | INFO | __main__::1956 - 应用程序启动 +2025-08-27 20:44:01.530 | INFO | __main__:load_git_config:1243 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 20:44:01.531 | INFO | __main__:load_django_config:1865 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 20:44:03.329 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:44:03.419 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 20:44:05.993 | INFO | __main__:run:730 - 开始检查防火墙状态 +2025-08-27 20:44:06.007 | ERROR | __main__:run:750 - 检查防火墙状态失败: 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-27 20:44:06.010 | INFO | __main__:on_check_firewall_result:1459 - 检查防火墙结果: False - 检查防火墙状态失败: 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-27 20:45:12.537 | INFO | __main__::1989 - 应用程序启动 +2025-08-27 20:45:12.575 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 20:45:12.576 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 20:45:14.242 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 20:45:14.329 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 20:45:16.464 | INFO | __main__:run:736 - 开始检查防火墙状态 +2025-08-27 20:45:21.822 | INFO | __main__:show_firewall_password_dialog:1410 - 用户已输入sudo密码 +2025-08-27 20:45:22.005 | INFO | __main__:run:758 - 防火墙未启动 +2025-08-27 20:45:22.008 | INFO | __main__:on_check_firewall_result:1492 - 检查防火墙结果: True - 防火墙未启动 +Status: inactive +2025-08-27 20:45:29.644 | INFO | __main__:find_and_remember_settings_path:1865 - 正在查找settings.py文件位置... +2025-08-27 20:45:29.691 | INFO | __main__:find_and_remember_settings_path:1873 - 找到并记住settings.py文件: ./statuspage/settings.py +2025-08-27 20:45:29.693 | INFO | __main__:run:357 - 开始测试Django项目启动: ./statuspage +2025-08-27 20:45:29.693 | INFO | __main__:run:360 - 正在查找settings.py文件位置... +2025-08-27 20:45:29.770 | INFO | __main__:run:369 - 找到settings.py文件: ./statuspage/settings.py +2025-08-27 20:45:29.771 | INFO | __main__:run:370 - 项目目录: ./statuspage +2025-08-27 20:45:29.820 | INFO | __main__:run:395 - 检查Django安装状态... +2025-08-27 20:45:40.328 | INFO | __main__:run:412 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:45:40.330 | INFO | __main__:on_django_test_result:1798 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:45:55.132 | INFO | __main__:run:786 - 开始开放端口: 8000 +2025-08-27 20:45:59.385 | INFO | __main__:show_port_password_dialog:1468 - 用户已输入sudo密码 +2025-08-27 20:45:59.459 | INFO | __main__:run:796 - 开放端口 8000... +2025-08-27 20:45:59.662 | ERROR | __main__:run:820 - 验证端口开放状态失败 +2025-08-27 20:46:01.666 | INFO | __main__:on_open_port_result:1508 - 开放端口结果: False - 验证端口开放状态失败 +2025-08-27 20:50:38.933 | INFO | __main__:run:357 - 开始测试Django项目启动: ./statuspage +2025-08-27 20:50:38.934 | INFO | __main__:run:360 - 正在查找settings.py文件位置... +2025-08-27 20:50:38.981 | INFO | __main__:run:369 - 找到settings.py文件: ./statuspage/settings.py +2025-08-27 20:50:38.981 | INFO | __main__:run:370 - 项目目录: ./statuspage +2025-08-27 20:50:39.030 | INFO | __main__:run:395 - 检查Django安装状态... +2025-08-27 20:50:49.547 | INFO | __main__:run:412 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:50:49.548 | INFO | __main__:on_django_test_result:1798 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:50:57.952 | INFO | __main__:run:357 - 开始测试Django项目启动: ./statuspage +2025-08-27 20:50:57.952 | INFO | __main__:run:360 - 正在查找settings.py文件位置... +2025-08-27 20:50:57.993 | INFO | __main__:run:369 - 找到settings.py文件: ./statuspage/settings.py +2025-08-27 20:50:57.994 | INFO | __main__:run:370 - 项目目录: ./statuspage +2025-08-27 20:50:58.042 | INFO | __main__:run:395 - 检查Django安装状态... +2025-08-27 20:51:08.550 | INFO | __main__:run:412 - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:51:08.551 | INFO | __main__:on_django_test_result:1798 - Django测试结果: True - Django服务器启动测试成功,可以在0.0.0.0:8000访问 +2025-08-27 20:51:26.381 | INFO | __main__:run:537 - 开始收集静态文件: ./statuspage +2025-08-27 20:51:26.389 | INFO | __main__:run:548 - 检查Django安装状态... +2025-08-27 20:51:27.202 | INFO | __main__:on_collect_static_result:1853 - 收集静态文件结果: True - 静态文件收集成功: + +127 static files copied to '/home/xiaji/home/xiaji/static'. + +2025-08-27 20:51:27.202 | INFO | __main__:run:569 - 静态文件收集成功 +2025-08-27 20:52:00.408 | INFO | __main__:run:443 - 开始下载settings.py文件: ./statuspage/settings.py +2025-08-27 20:52:00.466 | INFO | __main__:run:466 - settings.py文件下载成功 +2025-08-27 20:52:00.476 | INFO | __main__:on_download_settings_result:1819 - settings.py已保存到本地: settings_backup_20250827_205200.py +2025-08-27 20:52:00.476 | INFO | __main__:on_download_settings_result:1827 - 下载settings.py结果: True - settings.py文件下载成功 +2025-08-27 20:52:27.642 | INFO | __main__:run:489 - 开始上传settings.py文件: ./statuspage/settings.py +2025-08-27 20:52:27.670 | INFO | __main__:run:516 - settings.py文件上传成功,原文件已备份到: ./statuspage/settings_backup_20250827_205227.py +2025-08-27 20:52:27.671 | INFO | __main__:on_upload_settings_result:1840 - 上传settings.py结果: True - settings.py文件上传成功,原文件已备份到: ./statuspage/settings_backup_20250827_205227.py +2025-08-27 20:52:32.483 | INFO | __main__:run:537 - 开始收集静态文件: ./statuspage +2025-08-27 20:52:32.493 | INFO | __main__:run:548 - 检查Django安装状态... +2025-08-27 20:52:33.288 | INFO | __main__:run:569 - 静态文件收集成功 +2025-08-27 20:52:33.289 | INFO | __main__:on_collect_static_result:1853 - 收集静态文件结果: True - 静态文件收集成功: + +127 static files copied to '/home/xiaji/static'. + +2025-08-27 21:06:55.636 | INFO | __main__::2546 - 应用程序启动 +2025-08-27 21:06:55.679 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:06:55.680 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:06:55.681 | INFO | __main__:load_gunicorn_config:2451 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:08:14.982 | INFO | __main__::2546 - 应用程序启动 +2025-08-27 21:08:15.012 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:08:15.013 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:08:15.016 | INFO | __main__:load_gunicorn_config:2451 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:08:16.792 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:08:16.884 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:08:51.818 | INFO | __main__:run:1919 - 开始安装Gunicorn +2025-08-27 21:08:57.805 | INFO | __main__:show_gunicorn_password_dialog:2324 - 用户已输入sudo密码 +2025-08-27 21:08:57.863 | INFO | __main__:run:1937 - Gunicorn未安装,开始安装gunicorn +2025-08-27 21:08:58.321 | ERROR | __main__:run:1942 - Gunicorn安装失败: [sudo] password for xiaji: 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-27 21:08:58.327 | INFO | __main__:on_gunicorn_install_result:2383 - Gunicorn安装结果: False - Gunicorn安装失败: [sudo] password for xiaji: 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-27 21:09:29.032 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:09:34.847 | INFO | __main__:show_service_password_dialog:2346 - 用户已输入sudo密码 +2025-08-27 21:09:34.902 | ERROR | __main__:run:2103 - Gunicorn服务status操作失败: [sudo] password for xiaji: Unit gunicorn.service could not be found. + +2025-08-27 21:09:34.903 | INFO | __main__:on_manage_service_result:2428 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: Unit gunicorn.service could not be found. + +2025-08-27 21:09:59.573 | INFO | __main__::2546 - 应用程序启动 +2025-08-27 21:09:59.616 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:09:59.618 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:09:59.619 | INFO | __main__:load_gunicorn_config:2451 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:10:01.671 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:10:01.769 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:10:08.156 | INFO | __main__:run:1919 - 开始安装Gunicorn +2025-08-27 21:10:12.554 | INFO | __main__:show_gunicorn_password_dialog:2324 - 用户已输入sudo密码 +2025-08-27 21:10:12.616 | INFO | __main__:run:1937 - Gunicorn未安装,开始安装gunicorn +2025-08-27 21:10:28.248 | INFO | __main__:run:1951 - Gunicorn安装成功,版本: gunicorn (version 23.0.0) +2025-08-27 21:10:28.251 | INFO | __main__:on_gunicorn_install_result:2383 - Gunicorn安装结果: True - Gunicorn安装成功,版本: gunicorn (version 23.0.0) +2025-08-27 21:10:42.627 | INFO | __main__:run:1974 - 开始测试Gunicorn运行,项目目录: /home/xiaji/ +2025-08-27 21:10:52.760 | INFO | __main__:run:1985 - Gunicorn测试运行成功 +2025-08-27 21:10:52.765 | INFO | __main__:on_gunicorn_test_result:2396 - Gunicorn测试结果: True - Gunicorn测试运行成功 +项目: statuspage +目录: /home/xiaji/ +绑定: 0.0.0.0:8000 +2025-08-27 21:10:56.336 | INFO | __main__:run:1974 - 开始测试Gunicorn运行,项目目录: /home/xiaji/ +2025-08-27 21:11:06.468 | INFO | __main__:run:1985 - Gunicorn测试运行成功 +2025-08-27 21:11:06.469 | INFO | __main__:on_gunicorn_test_result:2396 - Gunicorn测试结果: True - Gunicorn测试运行成功 +项目: statuspage +目录: /home/xiaji/ +绑定: 0.0.0.0:8000 +2025-08-27 21:11:13.512 | INFO | __main__:run:1974 - 开始测试Gunicorn运行,项目目录: /home/xiaji/ +2025-08-27 21:11:23.641 | INFO | __main__:run:1985 - Gunicorn测试运行成功 +2025-08-27 21:11:23.642 | INFO | __main__:on_gunicorn_test_result:2396 - Gunicorn测试结果: True - Gunicorn测试运行成功 +项目: statuspage +目录: /home/xiaji/ +绑定: 0.0.0.0:8000 +2025-08-27 21:12:46.221 | INFO | __main__:find_and_remember_settings_path:1865 - 正在查找settings.py文件位置... +2025-08-27 21:12:46.267 | INFO | __main__:find_and_remember_settings_path:1873 - 找到并记住settings.py文件: ./statuspage/settings.py +2025-08-27 21:12:46.269 | INFO | __main__:run:443 - 开始下载settings.py文件: ./statuspage/settings.py +2025-08-27 21:12:46.366 | INFO | __main__:run:466 - settings.py文件下载成功 +2025-08-27 21:12:46.374 | INFO | __main__:on_download_settings_result:1819 - settings.py已保存到本地: settings_backup_20250827_211246.py +2025-08-27 21:12:46.374 | INFO | __main__:on_download_settings_result:1827 - 下载settings.py结果: True - settings.py文件下载成功 +2025-08-27 21:16:10.875 | INFO | __main__:run:2014 - 开始上传Gunicorn systemd服务文件 +2025-08-27 21:16:15.314 | INFO | __main__:show_service_password_dialog:2346 - 用户已输入sudo密码 +2025-08-27 21:16:15.532 | INFO | __main__:run:2050 - Gunicorn systemd服务文件上传成功 +2025-08-27 21:16:15.533 | INFO | __main__:on_upload_service_result:2409 - 上传服务文件结果: True - Gunicorn systemd服务文件上传成功 +2025-08-27 21:16:22.515 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: enable +2025-08-27 21:16:26.948 | INFO | __main__:show_service_password_dialog:2346 - 用户已输入sudo密码 +2025-08-27 21:16:27.303 | INFO | __main__:run:2099 - Gunicorn服务enable操作成功 +2025-08-27 21:16:27.304 | INFO | __main__:on_manage_service_result:2428 - Gunicorn服务管理结果: True - Gunicorn服务enable操作成功 +2025-08-27 21:16:28.462 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: start +2025-08-27 21:16:32.810 | INFO | __main__:show_service_password_dialog:2346 - 用户已输入sudo密码 +2025-08-27 21:16:32.922 | INFO | __main__:run:2099 - Gunicorn服务start操作成功 +2025-08-27 21:16:32.923 | INFO | __main__:on_manage_service_result:2428 - Gunicorn服务管理结果: True - Gunicorn服务start操作成功 +2025-08-27 21:16:34.423 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:16:38.963 | INFO | __main__:show_service_password_dialog:2346 - 用户已输入sudo密码 +2025-08-27 21:16:38.994 | ERROR | __main__:run:2103 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:16:38.995 | INFO | __main__:on_manage_service_result:2428 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:17:15.645 | INFO | __main__::2547 - 应用程序启动 +2025-08-27 21:17:15.687 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:17:15.689 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:17:15.690 | INFO | __main__:load_gunicorn_config:2452 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:17:17.514 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:17:17.614 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:17:20.576 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:17:25.390 | INFO | __main__:show_service_password_dialog:2347 - 用户已输入sudo密码 +2025-08-27 21:17:25.419 | INFO | __main__:on_manage_service_result:2429 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: +2025-08-27 21:17:25.419 | ERROR | __main__:run:2104 - Gunicorn服务status操作失败: +2025-08-27 21:17:54.474 | INFO | __main__::2549 - 应用程序启动 +2025-08-27 21:17:54.512 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:17:54.513 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:17:54.514 | INFO | __main__:load_gunicorn_config:2454 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:17:56.817 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:17:56.914 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:17:58.962 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:18:41.193 | INFO | __main__:run:1974 - 开始测试Gunicorn运行,项目目录: /home/xiaji/ +2025-08-27 21:18:51.322 | INFO | __main__:run:1985 - Gunicorn测试运行成功 +2025-08-27 21:18:51.324 | INFO | __main__:on_gunicorn_test_result:2399 - Gunicorn测试结果: True - Gunicorn测试运行成功 +项目: statuspage +目录: /home/xiaji/ +绑定: 0.0.0.0:8000 +2025-08-27 21:18:58.906 | INFO | __main__:run:671 - 开始设置时区为北京时区并重启服务器 +2025-08-27 21:19:02.375 | INFO | __main__:show_password_dialog:1358 - 用户已输入sudo密码 +2025-08-27 21:19:02.442 | INFO | __main__:run:681 - 设置时区为Asia/Shanghai... +2025-08-27 21:19:02.587 | INFO | __main__:run:694 - 当前时区: Asia/Shanghai +2025-08-27 21:19:02.587 | INFO | __main__:run:702 - 开始重启服务器... +2025-08-27 21:19:02.654 | INFO | __main__:run:713 - 时区已设置为北京时区,服务器正在重启中... +2025-08-27 21:19:04.155 | INFO | __main__:on_set_timezone_and_restart_result:1384 - 设置时区和重启服务器结果: True - 时区已设置为北京时区,服务器正在重启中... +2025-08-27 21:19:49.291 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:19:49.434 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:21:05.121 | INFO | __main__::2557 - 应用程序启动 +2025-08-27 21:21:05.158 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:21:05.159 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:21:05.160 | INFO | __main__:load_gunicorn_config:2462 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:21:15.903 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:21:15.991 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:21:37.089 | INFO | __main__::2557 - 应用程序启动 +2025-08-27 21:21:37.123 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:21:37.123 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:21:37.125 | INFO | __main__:load_gunicorn_config:2462 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:21:39.243 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:21:39.332 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:21:51.029 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:22:02.555 | INFO | __main__:run:1974 - 开始测试Gunicorn运行,项目目录: /home/xiaji/ +2025-08-27 21:22:12.692 | INFO | __main__:run:1985 - Gunicorn测试运行成功 +2025-08-27 21:22:12.694 | INFO | __main__:on_gunicorn_test_result:2406 - Gunicorn测试结果: True - Gunicorn测试运行成功 +项目: statuspage +目录: /home/xiaji/ +绑定: 0.0.0.0:8000 +2025-08-27 21:37:09.634 | INFO | __main__::2577 - 应用程序启动 +2025-08-27 21:37:09.672 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:37:09.673 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:37:09.675 | INFO | __main__:load_gunicorn_config:2462 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:38:00.187 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:38:00.283 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:38:04.230 | INFO | __main__:on_tab_changed:2570 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:38:04.736 | INFO | __main__:check_service_status:2470 - 自动检测Gunicorn服务状态 +2025-08-27 21:38:04.741 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:41:20.289 | INFO | __main__::2576 - 应用程序启动 +2025-08-27 21:41:20.322 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:41:20.323 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:41:20.325 | INFO | __main__:load_gunicorn_config:2461 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:41:57.023 | INFO | __main__::2576 - 应用程序启动 +2025-08-27 21:41:57.057 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:41:57.058 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:41:57.061 | INFO | __main__:load_gunicorn_config:2461 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:41:59.413 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:41:59.498 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:42:01.010 | INFO | __main__:on_tab_changed:2569 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:42:01.512 | INFO | __main__:check_service_status:2469 - 自动检测Gunicorn服务状态 +2025-08-27 21:42:01.750 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:42:06.555 | INFO | __main__:show_service_password_dialog:2354 - 用户已输入sudo密码 +2025-08-27 21:42:06.613 | ERROR | __main__:run:2104 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:42:06.614 | INFO | __main__:on_manage_service_result:2438 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:42:39.942 | INFO | __main__::2581 - 应用程序启动 +2025-08-27 21:42:39.982 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:42:39.983 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:42:39.984 | INFO | __main__:load_gunicorn_config:2466 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:42:52.012 | INFO | __main__::2581 - 应用程序启动 +2025-08-27 21:42:52.062 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:42:52.063 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:42:52.064 | INFO | __main__:load_gunicorn_config:2466 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:42:53.954 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:42:54.039 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:42:55.018 | INFO | __main__:on_tab_changed:2574 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:42:55.511 | INFO | __main__:check_service_status:2474 - 自动检测Gunicorn服务状态 +2025-08-27 21:42:55.729 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:43:00.740 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:43:00.793 | ERROR | __main__:run:2109 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:43:00.795 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:43:04.162 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: daemon-reload +2025-08-27 21:43:08.473 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:43:08.512 | ERROR | __main__:run:2109 - Gunicorn服务daemon-reload操作失败: [sudo] password for xiaji: Too many arguments. + +2025-08-27 21:43:08.513 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务daemon-reload操作失败: [sudo] password for xiaji: Too many arguments. + +2025-08-27 21:43:10.549 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:43:13.633 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:43:13.700 | ERROR | __main__:run:2109 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:43:13.702 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:44:29.302 | INFO | __main__::2581 - 应用程序启动 +2025-08-27 21:44:29.339 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:44:29.340 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:44:29.341 | INFO | __main__:load_gunicorn_config:2466 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:44:31.199 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:44:31.286 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:44:32.714 | INFO | __main__:on_tab_changed:2574 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:44:33.215 | INFO | __main__:check_service_status:2474 - 自动检测Gunicorn服务状态 +2025-08-27 21:44:33.462 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:44:39.041 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:44:39.115 | ERROR | __main__:run:2109 - Gunicorn服务status操作失败: 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-27 21:44:39.117 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: 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-27 21:44:43.001 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:44:47.532 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:44:47.556 | ERROR | __main__:run:2109 - Gunicorn服务status操作失败: 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-27 21:44:47.557 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: 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-27 21:45:22.587 | INFO | __main__::2581 - 应用程序启动 +2025-08-27 21:45:22.620 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:45:22.621 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:45:22.623 | INFO | __main__:load_gunicorn_config:2466 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:45:24.555 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:45:24.646 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:45:25.676 | INFO | __main__:on_tab_changed:2574 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:45:26.170 | INFO | __main__:check_service_status:2474 - 自动检测Gunicorn服务状态 +2025-08-27 21:45:26.470 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:45:32.466 | INFO | __main__:show_service_password_dialog:2359 - 用户已输入sudo密码 +2025-08-27 21:45:32.543 | ERROR | __main__:run:2109 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:45:32.552 | INFO | __main__:on_manage_service_result:2443 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:45:35.574 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:45:36.964 | INFO | __main__:show_service_password_dialog:2371 - 用户取消了密码输入 +2025-08-27 21:47:15.297 | INFO | __main__::2574 - 应用程序启动 +2025-08-27 21:47:15.354 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:47:15.355 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:47:15.357 | INFO | __main__:load_gunicorn_config:2459 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:47:52.100 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:47:52.193 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:47:53.480 | INFO | __main__:on_tab_changed:2567 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:47:53.980 | INFO | __main__:check_service_status:2467 - 自动检测Gunicorn服务状态 +2025-08-27 21:47:54.223 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:47:59.494 | INFO | __main__:show_service_password_dialog:2352 - 用户已输入sudo密码 +2025-08-27 21:47:59.596 | ERROR | __main__:run:2102 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:47:59.601 | INFO | __main__:on_manage_service_result:2436 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:02.598 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:48:06.136 | INFO | __main__:show_service_password_dialog:2352 - 用户已输入sudo密码 +2025-08-27 21:48:06.260 | ERROR | __main__:run:2102 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:06.261 | INFO | __main__:on_manage_service_result:2436 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:20.021 | INFO | __main__::2576 - 应用程序启动 +2025-08-27 21:48:20.057 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:48:20.058 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:48:20.059 | INFO | __main__:load_gunicorn_config:2461 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:48:33.185 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:48:33.272 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:48:34.629 | INFO | __main__:on_tab_changed:2569 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:48:35.123 | INFO | __main__:check_service_status:2469 - 自动检测Gunicorn服务状态 +2025-08-27 21:48:35.368 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:48:39.149 | INFO | __main__:show_service_password_dialog:2354 - 用户已输入sudo密码 +2025-08-27 21:48:39.229 | ERROR | __main__:run:2104 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:39.230 | INFO | __main__:on_manage_service_result:2438 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:40.738 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:48:45.799 | INFO | __main__:show_service_password_dialog:2354 - 用户已输入sudo密码 +2025-08-27 21:48:45.891 | ERROR | __main__:run:2104 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:45.894 | INFO | __main__:on_manage_service_result:2438 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:52.321 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:48:57.015 | INFO | __main__:show_service_password_dialog:2354 - 用户已输入sudo密码 +2025-08-27 21:48:57.085 | ERROR | __main__:run:2104 - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:48:57.086 | INFO | __main__:on_manage_service_result:2438 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: [sudo] password for xiaji: +2025-08-27 21:49:12.442 | INFO | __main__::2576 - 应用程序启动 +2025-08-27 21:49:12.488 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:49:12.489 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:49:12.490 | INFO | __main__:load_gunicorn_config:2461 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:49:18.363 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:49:18.456 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:49:21.130 | INFO | __main__:on_tab_changed:2569 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:49:21.635 | INFO | __main__:check_service_status:2469 - 自动检测Gunicorn服务状态 +2025-08-27 21:49:21.641 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:49:26.161 | INFO | __main__:show_service_password_dialog:2354 - 用户已输入sudo密码 +2025-08-27 21:50:03.244 | INFO | __main__::2597 - 应用程序启动 +2025-08-27 21:50:03.279 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:50:03.280 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:50:03.281 | INFO | __main__:load_gunicorn_config:2482 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:50:25.577 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:50:25.662 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:50:25.772 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:50:25.865 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:50:27.575 | INFO | __main__:on_tab_changed:2590 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:50:28.082 | INFO | __main__:check_service_status:2490 - 自动检测Gunicorn服务状态 +2025-08-27 21:50:28.304 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:50:33.275 | INFO | __main__:show_service_password_dialog:2375 - 用户已输入sudo密码 +2025-08-27 21:50:33.468 | ERROR | __main__:run:2125 - Gunicorn服务status操作失败: +2025-08-27 21:50:33.472 | INFO | __main__:on_manage_service_result:2459 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: +2025-08-27 21:50:53.983 | INFO | __main__::2587 - 应用程序启动 +2025-08-27 21:50:54.023 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:50:54.023 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:50:54.025 | INFO | __main__:load_gunicorn_config:2472 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 21:51:22.091 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 21:51:22.181 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 21:51:23.177 | INFO | __main__:on_tab_changed:2580 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 21:51:23.670 | INFO | __main__:check_service_status:2480 - 自动检测Gunicorn服务状态 +2025-08-27 21:51:23.914 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 21:51:28.274 | INFO | __main__:show_service_password_dialog:2365 - 用户已输入sudo密码 +2025-08-27 21:52:21.096 | INFO | __main__::2589 - 应用程序启动 +2025-08-27 21:52:21.141 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 21:52:21.142 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 21:52:21.143 | INFO | __main__:load_gunicorn_config:2474 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:07:09.891 | INFO | __main__::2589 - 应用程序启动 +2025-08-27 22:07:09.921 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:07:09.924 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:07:09.925 | INFO | __main__:load_gunicorn_config:2474 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:07:12.485 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:07:12.573 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 22:07:14.086 | INFO | __main__:on_tab_changed:2582 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:07:14.582 | INFO | __main__:check_service_status:2482 - 自动检测Gunicorn服务状态 +2025-08-27 22:07:14.810 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 22:07:44.991 | INFO | __main__::2589 - 应用程序启动 +2025-08-27 22:07:45.035 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:07:45.037 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:07:45.039 | INFO | __main__:load_gunicorn_config:2474 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:07:46.612 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:07:46.698 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 22:07:47.830 | INFO | __main__:on_tab_changed:2582 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:07:48.330 | INFO | __main__:check_service_status:2482 - 自动检测Gunicorn服务状态 +2025-08-27 22:07:48.546 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 22:09:24.972 | INFO | __main__::2587 - 应用程序启动 +2025-08-27 22:09:25.010 | INFO | __main__:load_git_config:1256 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:09:25.011 | INFO | __main__:load_django_config:1898 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:09:25.012 | INFO | __main__:load_gunicorn_config:2472 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:09:26.577 | INFO | __main__:run:68 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:09:26.668 | INFO | __main__:run:74 - 服务器连接成功 +2025-08-27 22:09:32.521 | INFO | __main__:on_tab_changed:2580 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:09:33.021 | INFO | __main__:check_service_status:2480 - 自动检测Gunicorn服务状态 +2025-08-27 22:09:33.022 | INFO | __main__:manage_service:2313 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:09:33.250 | INFO | __main__:manage_service:2333 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:09:33.250 | INFO | __main__:run:2074 - 开始执行Gunicorn服务操作: status +2025-08-27 22:09:40.208 | INFO | __main__:show_service_password_dialog:2365 - 用户已输入sudo密码 +2025-08-27 22:13:56.872 | INFO | __main__::2600 - 应用程序启动 +2025-08-27 22:13:56.910 | INFO | __main__:load_git_config:1257 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:13:56.911 | INFO | __main__:load_django_config:1899 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:13:56.913 | INFO | __main__:load_gunicorn_config:2485 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:13:58.882 | INFO | __main__:run:69 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:13:58.970 | INFO | __main__:run:75 - 服务器连接成功 +2025-08-27 22:14:01.498 | INFO | __main__:on_tab_changed:2593 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:14:02.001 | INFO | __main__:check_service_status:2493 - 自动检测Gunicorn服务状态 +2025-08-27 22:14:02.002 | INFO | __main__:manage_service:2326 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:14:02.217 | INFO | __main__:manage_service:2346 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:14:02.218 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-27 22:14:36.463 | INFO | __main__:show_service_password_dialog:2378 - 用户已输入sudo密码 +2025-08-27 22:15:06.605 | ERROR | __main__:run:2098 - 命令执行超时: sudo -S systemctl status gunicorn +2025-08-27 22:15:06.607 | ERROR | __main__:run:2129 - Gunicorn服务status操作失败: 命令执行超时(30秒): sudo -S systemctl status gunicorn +2025-08-27 22:15:06.615 | INFO | __main__:on_manage_service_result:2462 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: 命令执行超时(30秒): sudo -S systemctl status gunicorn +2025-08-27 22:24:36.179 | INFO | __main__::2608 - 应用程序启动 +2025-08-27 22:24:36.224 | INFO | __main__:load_git_config:1257 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:24:36.224 | INFO | __main__:load_django_config:1899 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:24:36.227 | INFO | __main__:load_gunicorn_config:2493 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:24:49.405 | INFO | __main__:run:69 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:24:49.500 | INFO | __main__:run:75 - 服务器连接成功 +2025-08-27 22:24:50.639 | INFO | __main__:on_tab_changed:2601 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:24:51.149 | INFO | __main__:check_service_status:2501 - 自动检测Gunicorn服务状态 +2025-08-27 22:24:51.150 | INFO | __main__:manage_service:2334 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:24:51.388 | INFO | __main__:manage_service:2354 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:24:51.389 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-27 22:24:55.839 | INFO | __main__:show_service_password_dialog:2386 - 用户已输入sudo密码 +2025-08-27 22:25:25.941 | ERROR | __main__:run:2104 - 命令执行超时: sudo -S systemctl status gunicorn +2025-08-27 22:25:25.942 | ERROR | __main__:run:2137 - Gunicorn服务status操作失败: 命令执行超时(30秒): sudo -S systemctl status gunicorn +2025-08-27 22:25:25.944 | INFO | __main__:on_manage_service_result:2470 - Gunicorn服务管理结果: False - Gunicorn服务status操作失败: 命令执行超时(30秒): sudo -S systemctl status gunicorn +2025-08-27 22:28:02.231 | INFO | __main__:load_git_config:1257 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:28:02.232 | INFO | __main__:load_django_config:1899 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:28:02.233 | INFO | __main__:load_gunicorn_config:2507 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:28:03.873 | INFO | __main__:run:69 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:28:03.963 | INFO | __main__:run:75 - 服务器连接成功 +2025-08-27 22:28:05.153 | INFO | __main__:on_tab_changed:2615 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:28:05.652 | INFO | __main__:check_service_status:2515 - 自动检测Gunicorn服务状态 +2025-08-27 22:28:05.653 | INFO | __main__:manage_service:2348 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:28:05.901 | INFO | __main__:manage_service:2368 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:28:05.903 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-27 22:28:08.849 | INFO | __main__:show_service_password_dialog:2400 - 用户已输入sudo密码 diff --git a/app.log b/app.log new file mode 100644 index 0000000..eb7d455 --- /dev/null +++ b/app.log @@ -0,0 +1,67 @@ +2025-08-27 22:29:13.339 | INFO | __main__::2691 - 应用程序启动 +2025-08-27 22:29:13.376 | INFO | __main__:load_git_config:1257 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-27 22:29:13.377 | INFO | __main__:load_django_config:1899 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-27 22:29:13.379 | INFO | __main__:load_gunicorn_config:2576 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-27 22:29:15.654 | INFO | __main__:on_tab_changed:2684 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:29:16.159 | WARNING | __main__:check_service_status:2587 - 未连接服务器,跳过Gunicorn服务状态检测 +2025-08-27 22:29:20.590 | INFO | __main__:run:69 - 尝试连接服务器: 192.168.3.157:22 +2025-08-27 22:29:20.678 | INFO | __main__:run:75 - 服务器连接成功 +2025-08-27 22:29:21.205 | INFO | __main__:on_tab_changed:2684 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:29:21.708 | INFO | __main__:check_service_status:2584 - 自动检测Gunicorn服务状态 +2025-08-27 22:29:21.708 | INFO | __main__:manage_service:2417 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:29:21.947 | INFO | __main__:manage_service:2437 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:29:21.954 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-27 22:29:26.166 | INFO | __main__:show_service_password_dialog:2469 - 用户已输入sudo密码 +2025-08-27 22:29:26.185 | DEBUG | __main__:run:2087 - 准备执行命令: sudo -S systemctl status gunicorn +2025-08-27 22:29:26.787 | DEBUG | __main__:run:2101 - 正在传递sudo密码... +2025-08-27 22:29:26.788 | DEBUG | __main__:run:2104 - 密码传递完成,等待命令执行... +2025-08-27 22:29:56.835 | ERROR | __main__:run:2119 - 命令执行超时: sudo -S systemctl status gunicorn +2025-08-27 22:30:37.721 | INFO | __main__:on_tab_changed:2684 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-27 22:30:38.215 | INFO | __main__:check_service_status:2584 - 自动检测Gunicorn服务状态 +2025-08-27 22:30:38.216 | INFO | __main__:manage_service:2417 - 开始管理Gunicorn服务,操作: status +2025-08-27 22:30:38.218 | INFO | __main__:manage_service:2437 - ManageGunicornServiceThread已启动,操作: status +2025-08-27 22:30:38.220 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-27 22:30:41.127 | INFO | __main__:show_service_password_dialog:2469 - 用户已输入sudo密码 +2025-08-27 22:30:41.134 | DEBUG | __main__:run:2087 - 准备执行命令: sudo -S systemctl status gunicorn +2025-08-27 22:30:41.727 | DEBUG | __main__:run:2101 - 正在传递sudo密码... +2025-08-27 22:30:41.727 | DEBUG | __main__:run:2104 - 密码传递完成,等待命令执行... +2025-08-27 22:31:11.761 | ERROR | __main__:run:2119 - 命令执行超时: sudo -S systemctl status gunicorn +2025-08-28 20:04:06.090 | INFO | __main__::2691 - 应用程序启动 +2025-08-28 20:04:06.159 | INFO | __main__:load_git_config:1257 - 已加载服务器 测试服务器(192.168.3.157) 的git配置 +2025-08-28 20:04:06.160 | INFO | __main__:load_django_config:1899 - 已加载服务器 测试服务器(192.168.3.157) 的Django配置 +2025-08-28 20:04:06.161 | INFO | __main__:load_gunicorn_config:2576 - 已加载服务器 测试服务器(192.168.3.157) 的Gunicorn配置 +2025-08-28 20:04:07.908 | INFO | __main__:run:69 - 尝试连接服务器: 192.168.3.157:22 +2025-08-28 20:04:08.017 | INFO | __main__:run:75 - 服务器连接成功 +2025-08-28 20:04:11.660 | INFO | __main__:on_tab_changed:2684 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:04:12.159 | INFO | __main__:check_service_status:2584 - 自动检测Gunicorn服务状态 +2025-08-28 20:04:12.159 | INFO | __main__:manage_service:2417 - 开始管理Gunicorn服务,操作: status +2025-08-28 20:04:12.161 | INFO | __main__:manage_service:2437 - ManageGunicornServiceThread已启动,操作: status +2025-08-28 20:04:12.162 | INFO | __main__:run:2075 - 开始执行Gunicorn服务操作: status +2025-08-28 20:04:15.634 | INFO | __main__:show_service_password_dialog:2469 - 用户已输入sudo密码 +2025-08-28 20:04:15.686 | DEBUG | __main__:run:2087 - 准备执行命令: sudo -S systemctl status gunicorn +2025-08-28 20:04:16.326 | DEBUG | __main__:run:2101 - 正在传递sudo密码... +2025-08-28 20:04:16.327 | DEBUG | __main__:run:2104 - 密码传递完成,等待命令执行... +2025-08-28 20:28:50.493 | INFO | __main__::114 - 应用程序启动 +2025-08-28 20:32:04.868 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 +2025-08-28 20:32:06.089 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:32:06.620 | ERROR | gunicorn_tab:on_manage_service_result:270 - 服务操作失败: 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:32:06.620 | ERROR | threads:run:808 - 服务状态查询失败: 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:32:29.596 | INFO | __main__:on_tab_changed:107 - 切换到Gunicorn标签,自动检测服务状态 +2025-08-28 20:32:30.115 | ERROR | threads:run:808 - 服务状态查询失败: 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:32:30.115 | ERROR | gunicorn_tab:on_manage_service_result:270 - 服务操作失败: 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:35:01.275 | ERROR | threads:run:808 - 服务状态查询失败: 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:35:01.275 | ERROR | gunicorn_tab:on_manage_service_result:270 - 服务操作失败: 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:37:01.109 | INFO | __main__::114 - 应用程序启动 +2025-08-28 20:41:24.800 | INFO | threads:run:47 - SSH连接成功: 192.168.3.157 diff --git a/config.json b/config.json new file mode 100644 index 0000000..30ac249 --- /dev/null +++ b/config.json @@ -0,0 +1,25 @@ +{ + "servers": [ + { + "alias": "测试服务器(192.168.3.157)", + "host": "192.168.3.157", + "port": 22, + "username": "xiaji", + "password": "xiaji", + "project_name": "statuspage", + "git_url": "http://192.168.3.241:3000/xiaji/webstatus", + "remote_directory": "/home/xiaji/", + "django_path": "/home/xiaji/" + }, + { + "alias": "生产服务器", + "host": "192.168.1.200", + "port": 22, + "username": "admin", + "password": "your_password", + "project_name": "production_app", + "git_url": "https://github.com/example/production_app.git", + "remote_directory": "/home/admin/production_app" + } + ] +} \ No newline at end of file diff --git a/django_tab.py b/django_tab.py new file mode 100644 index 0000000..60bd23d --- /dev/null +++ b/django_tab.py @@ -0,0 +1,277 @@ +import os +from loguru import logger +from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, + QPushButton, QComboBox, QMessageBox, QTextEdit, + QGroupBox, QGridLayout, QProgressBar) +from PySide6.QtCore import Qt + +from threads import (DjangoInstallThread, DjangoTestThread, DownloadSettingsThread, + UploadSettingsThread, CollectStaticThread, CheckDjangoStatusThread) + + +class DjangoTab(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.parent = parent + self.init_ui() + + def init_ui(self): + layout = QVBoxLayout() + + # Django项目配置组 + config_group = QGroupBox("Django项目配置") + config_layout = QGridLayout() + + config_layout.addWidget(QLabel("Django项目路径:"), 0, 0) + self.django_path_input = QLineEdit() + self.django_path_input.setPlaceholderText("/home/user/django_project") + config_layout.addWidget(self.django_path_input, 0, 1) + + self.load_django_path_btn = QPushButton("加载路径") + self.load_django_path_btn.clicked.connect(self.load_django_path) + config_layout.addWidget(self.load_django_path_btn, 0, 2) + + config_group.setLayout(config_layout) + layout.addWidget(config_group) + + # Django操作组 + django_group = QGroupBox("Django操作") + django_layout = QGridLayout() + + self.install_django_btn = QPushButton("安装Django") + self.install_django_btn.clicked.connect(self.install_django) + django_layout.addWidget(self.install_django_btn, 0, 0) + + self.test_django_btn = QPushButton("测试启动") + self.test_django_btn.clicked.connect(self.test_django) + django_layout.addWidget(self.test_django_btn, 0, 1) + + self.download_settings_btn = QPushButton("下载settings.py") + self.download_settings_btn.clicked.connect(self.download_settings) + django_layout.addWidget(self.download_settings_btn, 1, 0) + + self.upload_settings_btn = QPushButton("上传settings.py") + self.upload_settings_btn.clicked.connect(self.upload_settings) + django_layout.addWidget(self.upload_settings_btn, 1, 1) + + self.collect_static_btn = QPushButton("收集静态文件") + self.collect_static_btn.clicked.connect(self.collect_static) + django_layout.addWidget(self.collect_static_btn, 2, 0) + + self.check_status_btn = QPushButton("检查Django状态") + self.check_status_btn.clicked.connect(self.check_django_status) + django_layout.addWidget(self.check_status_btn, 2, 1) + + django_group.setLayout(django_layout) + layout.addWidget(django_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() + + self.output_text = QTextEdit() + self.output_text.setReadOnly(True) + self.output_text.setPlaceholderText("操作结果将在这里显示...") + output_layout.addWidget(self.output_text) + + # 进度条 + self.progress_bar = QProgressBar() + self.progress_bar.setVisible(False) + output_layout.addWidget(self.progress_bar) + + output_group.setLayout(output_layout) + layout.addWidget(output_group) + + layout.addStretch() + self.setLayout(layout) + + # 加载Django路径 + 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) + + def check_ssh_connection(self): + if not self.parent or not self.parent.ssh_client: + QMessageBox.warning(self, "警告", "请先连接服务器") + return False + return True + + def install_django(self): + if not self.check_ssh_connection(): + return + + self.output_text.append("正在安装Django...") + self.install_django_btn.setEnabled(False) + self.progress_bar.setVisible(True) + self.progress_bar.setValue(0) + + self.django_install_thread = DjangoInstallThread(self.parent.ssh_client) + self.django_install_thread.progress_updated.connect(self.update_progress) + self.django_install_thread.result_ready.connect(self.on_install_django_result) + self.django_install_thread.start() + + def update_progress(self, value): + self.progress_bar.setValue(value) + + def on_install_django_result(self, success, message): + self.install_django_btn.setEnabled(True) + self.progress_bar.setVisible(False) + if success: + self.output_text.append(f"Django安装成功: {message}") + logger.info(f"Django安装成功: {message}") + else: + self.output_text.append(f"Django安装失败: {message}") + logger.error(f"Django安装失败: {message}") + + def test_django(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + if not django_path: + QMessageBox.warning(self, "警告", "请输入Django项目路径") + return + + self.output_text.append(f"正在测试启动Django项目 {django_path}...") + self.test_django_btn.setEnabled(False) + self.progress_bar.setVisible(True) + self.progress_bar.setValue(0) + + self.django_test_thread = DjangoTestThread(self.parent.ssh_client, django_path) + self.django_test_thread.progress_updated.connect(self.update_progress) + self.django_test_thread.result_ready.connect(self.on_test_django_result) + self.django_test_thread.start() + + def on_test_django_result(self, success, message): + self.test_django_btn.setEnabled(True) + self.progress_bar.setVisible(False) + if success: + self.output_text.append(f"Django测试启动成功: {message}") + logger.info(f"Django测试启动成功: {message}") + else: + self.output_text.append(f"Django测试启动失败: {message}") + logger.error(f"Django测试启动失败: {message}") + + def download_settings(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + if not django_path: + QMessageBox.warning(self, "警告", "请输入Django项目路径") + return + + self.output_text.append(f"正在下载settings.py从 {django_path}...") + self.download_settings_btn.setEnabled(False) + + self.download_thread = DownloadSettingsThread(self.parent.ssh_client, django_path) + self.download_thread.result_ready.connect(self.on_download_settings_result) + self.download_thread.start() + + def on_download_settings_result(self, success, message): + self.download_settings_btn.setEnabled(True) + if success: + self.settings_editor.setText(message) + self.output_text.append("settings.py下载成功") + logger.info("settings.py下载成功") + else: + self.output_text.append(f"settings.py下载失败: {message}") + logger.error(f"settings.py下载失败: {message}") + + def upload_settings(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + settings_content = self.settings_editor.toPlainText() + + if not django_path or not settings_content: + QMessageBox.warning(self, "警告", "请输入Django项目路径并编辑settings.py内容") + return + + self.output_text.append(f"正在上传settings.py到 {django_path}...") + self.upload_settings_btn.setEnabled(False) + + self.upload_thread = UploadSettingsThread(self.parent.ssh_client, django_path, settings_content) + self.upload_thread.result_ready.connect(self.on_upload_settings_result) + self.upload_thread.start() + + def on_upload_settings_result(self, success, message): + self.upload_settings_btn.setEnabled(True) + if success: + self.output_text.append("settings.py上传成功") + logger.info("settings.py上传成功") + else: + self.output_text.append(f"settings.py上传失败: {message}") + logger.error(f"settings.py上传失败: {message}") + + def collect_static(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + if not django_path: + QMessageBox.warning(self, "警告", "请输入Django项目路径") + return + + self.output_text.append(f"正在收集 {django_path} 的静态文件...") + self.collect_static_btn.setEnabled(False) + self.progress_bar.setVisible(True) + self.progress_bar.setValue(0) + + self.collect_thread = CollectStaticThread(self.parent.ssh_client, django_path) + self.collect_thread.progress_updated.connect(self.update_progress) + self.collect_thread.result_ready.connect(self.on_collect_static_result) + self.collect_thread.start() + + def on_collect_static_result(self, success, message): + self.collect_static_btn.setEnabled(True) + self.progress_bar.setVisible(False) + if success: + self.output_text.append(f"静态文件收集成功: {message}") + logger.info(f"静态文件收集成功: {message}") + else: + self.output_text.append(f"静态文件收集失败: {message}") + logger.error(f"静态文件收集失败: {message}") + + def check_django_status(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + if not django_path: + QMessageBox.warning(self, "警告", "请输入Django项目路径") + return + + self.output_text.append(f"正在检查 {django_path} 的Django状态...") + self.check_status_btn.setEnabled(False) + + self.check_status_thread = CheckDjangoStatusThread(self.parent.ssh_client, django_path) + self.check_status_thread.result_ready.connect(self.on_check_django_status_result) + self.check_status_thread.start() + + def on_check_django_status_result(self, success, message): + self.check_status_btn.setEnabled(True) + if success: + self.output_text.append(f"Django状态检查结果:\n{message}") + logger.info("Django状态检查成功") + else: + self.output_text.append(f"Django状态检查失败: {message}") + logger.error(f"Django状态检查失败: {message}") + + def on_server_changed(self): + self.load_django_path() \ No newline at end of file diff --git a/gunicorn_tab.py b/gunicorn_tab.py new file mode 100644 index 0000000..a90423c --- /dev/null +++ b/gunicorn_tab.py @@ -0,0 +1,298 @@ +import os +from loguru import logger +from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, + QPushButton, QComboBox, QMessageBox, QTextEdit, + QGroupBox, QGridLayout, QProgressBar) +from PySide6.QtCore import Qt + +from threads import (GunicornInstallThread, GunicornTestThread, + UploadGunicornServiceThread, ManageGunicornServiceThread) + + +class GunicornTab(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.parent = parent + self.init_ui() + + def init_ui(self): + layout = QVBoxLayout() + + # Gunicorn配置组 + config_group = QGroupBox("Gunicorn配置") + config_layout = QGridLayout() + + config_layout.addWidget(QLabel("Django项目路径:"), 0, 0) + self.django_path_input = QLineEdit() + self.django_path_input.setPlaceholderText("/home/user/django_project") + config_layout.addWidget(self.django_path_input, 0, 1) + + config_layout.addWidget(QLabel("服务名称:"), 1, 0) + self.service_name_input = QLineEdit("django_gunicorn") + config_layout.addWidget(self.service_name_input, 1, 1) + + config_layout.addWidget(QLabel("端口:"), 2, 0) + self.port_input = QLineEdit("8000") + config_layout.addWidget(self.port_input, 2, 1) + + config_layout.addWidget(QLabel("工作进程数:"), 3, 0) + self.workers_input = QLineEdit("3") + config_layout.addWidget(self.workers_input, 3, 1) + + self.load_config_btn = QPushButton("加载配置") + self.load_config_btn.clicked.connect(self.load_gunicorn_config) + config_layout.addWidget(self.load_config_btn, 4, 1) + + config_group.setLayout(config_layout) + layout.addWidget(config_group) + + # Gunicorn操作组 + gunicorn_group = QGroupBox("Gunicorn操作") + gunicorn_layout = QGridLayout() + + self.install_gunicorn_btn = QPushButton("安装Gunicorn") + self.install_gunicorn_btn.clicked.connect(self.install_gunicorn) + gunicorn_layout.addWidget(self.install_gunicorn_btn, 0, 0) + + self.test_gunicorn_btn = QPushButton("测试Gunicorn") + self.test_gunicorn_btn.clicked.connect(self.test_gunicorn) + gunicorn_layout.addWidget(self.test_gunicorn_btn, 0, 1) + + self.upload_service_btn = QPushButton("上传服务文件") + self.upload_service_btn.clicked.connect(self.upload_service_file) + gunicorn_layout.addWidget(self.upload_service_btn, 1, 0) + + self.start_service_btn = QPushButton("启动服务") + self.start_service_btn.clicked.connect(lambda: self.manage_service("start")) + gunicorn_layout.addWidget(self.start_service_btn, 1, 1) + + self.stop_service_btn = QPushButton("停止服务") + self.stop_service_btn.clicked.connect(lambda: self.manage_service("stop")) + gunicorn_layout.addWidget(self.stop_service_btn, 2, 0) + + self.restart_service_btn = QPushButton("重启服务") + self.restart_service_btn.clicked.connect(lambda: self.manage_service("restart")) + gunicorn_layout.addWidget(self.restart_service_btn, 2, 1) + + self.status_service_btn = QPushButton("查看服务状态") + self.status_service_btn.clicked.connect(lambda: self.manage_service("status")) + gunicorn_layout.addWidget(self.status_service_btn, 3, 0) + + self.enable_service_btn = QPushButton("启用开机自启") + self.enable_service_btn.clicked.connect(lambda: self.manage_service("enable")) + gunicorn_layout.addWidget(self.enable_service_btn, 3, 1) + + gunicorn_group.setLayout(gunicorn_layout) + layout.addWidget(gunicorn_group) + + # 服务文件编辑器 + service_group = QGroupBox("Gunicorn服务文件") + service_layout = QVBoxLayout() + + self.service_editor = QTextEdit() + self.service_editor.setPlaceholderText("Gunicorn服务文件内容将在这里显示...") + service_layout.addWidget(self.service_editor) + + service_group.setLayout(service_layout) + layout.addWidget(service_group) + + # 操作输出 + output_group = QGroupBox("操作输出") + output_layout = QVBoxLayout() + + self.output_text = QTextEdit() + self.output_text.setReadOnly(True) + self.output_text.setPlaceholderText("操作结果将在这里显示...") + output_layout.addWidget(self.output_text) + + # 进度条 + self.progress_bar = QProgressBar() + self.progress_bar.setVisible(False) + output_layout.addWidget(self.progress_bar) + + output_group.setLayout(output_layout) + layout.addWidget(output_group) + + layout.addStretch() + self.setLayout(layout) + + # 加载Gunicorn配置 + 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) + + def generate_service_file(self, service_name, django_path, port, workers): + return f"""[Unit] +Description={service_name} daemon +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 + +[Install] +WantedBy=multi-user.target +""" + + def check_ssh_connection(self): + if not self.parent or not self.parent.ssh_client: + QMessageBox.warning(self, "警告", "请先连接服务器") + return False + return True + + def install_gunicorn(self): + if not self.check_ssh_connection(): + return + + self.output_text.append("正在安装Gunicorn...") + self.install_gunicorn_btn.setEnabled(False) + self.progress_bar.setVisible(True) + 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() + + self.gunicorn_install_thread = GunicornInstallThread(self.parent.ssh_client, password) + self.gunicorn_install_thread.progress_updated.connect(self.update_progress) + self.gunicorn_install_thread.result_ready.connect(self.on_install_gunicorn_result) + self.gunicorn_install_thread.start() + + def update_progress(self, value): + self.progress_bar.setValue(value) + + def on_install_gunicorn_result(self, success, message): + self.install_gunicorn_btn.setEnabled(True) + self.progress_bar.setVisible(False) + if success: + self.output_text.append(f"Gunicorn安装成功: {message}") + logger.info(f"Gunicorn安装成功: {message}") + else: + self.output_text.append(f"Gunicorn安装失败: {message}") + logger.error(f"Gunicorn安装失败: {message}") + + def test_gunicorn(self): + if not self.check_ssh_connection(): + return + + django_path = self.django_path_input.text().strip() + if not django_path: + QMessageBox.warning(self, "警告", "请输入Django项目路径") + return + + self.output_text.append(f"正在测试Gunicorn {django_path}...") + self.test_gunicorn_btn.setEnabled(False) + self.progress_bar.setVisible(True) + self.progress_bar.setValue(0) + + self.gunicorn_test_thread = GunicornTestThread(self.parent.ssh_client, django_path) + self.gunicorn_test_thread.progress_updated.connect(self.update_progress) + self.gunicorn_test_thread.result_ready.connect(self.on_test_gunicorn_result) + self.gunicorn_test_thread.start() + + def on_test_gunicorn_result(self, success, message): + self.test_gunicorn_btn.setEnabled(True) + self.progress_bar.setVisible(False) + if success: + self.output_text.append(f"Gunicorn测试成功: {message}") + logger.info(f"Gunicorn测试成功: {message}") + else: + self.output_text.append(f"Gunicorn测试失败: {message}") + logger.error(f"Gunicorn测试失败: {message}") + + def upload_service_file(self): + if not self.check_ssh_connection(): + return + + service_name = self.service_name_input.text().strip() + service_content = self.service_editor.toPlainText() + + if not service_name or not service_content: + 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() + + self.upload_thread = UploadGunicornServiceThread(self.parent.ssh_client, service_name, service_content, password) + self.upload_thread.result_ready.connect(self.on_upload_service_result) + self.upload_thread.start() + + def on_upload_service_result(self, success, message): + self.upload_service_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 manage_service(self, action): + if not self.check_ssh_connection(): + return + + service_name = self.service_name_input.text().strip() + if not service_name: + QMessageBox.warning(self, "警告", "请输入服务名称") + return + + self.output_text.append(f"正在执行服务 {action} 操作...") + + # 禁用所有服务管理按钮 + buttons = [self.start_service_btn, self.stop_service_btn, self.restart_service_btn, + self.status_service_btn, self.enable_service_btn] + for btn in buttons: + btn.setEnabled(False) + + # 获取密码 + password = None + if self.parent and hasattr(self.parent, 'server_connection_tab'): + password = self.parent.server_connection_tab.password_input.text() + + 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)) + self.manage_thread.start() + + def on_manage_service_result(self, success, message, buttons): + # 重新启用所有服务管理按钮 + for btn in buttons: + 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 on_server_changed(self): + self.load_gunicorn_config() + + def check_service_status(self): + if not self.check_ssh_connection(): + return + + service_name = self.service_name_input.text().strip() + if not service_name: + return + + self.manage_service("status") \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..7f5599a --- /dev/null +++ b/main.py @@ -0,0 +1,119 @@ +import sys +import os +from loguru import logger +from PySide6.QtWidgets import QApplication, QMainWindow, QTabWidget +from PySide6.QtCore import QTimer + +from server_connection_tab import ServerConnectionTab +from remote_command_tab import RemoteCommandTab +from django_tab import DjangoTab +from gunicorn_tab import GunicornTab + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("服务器管理工具") + self.setGeometry(100, 100, 800, 600) + + # 创建标签页 + self.tab_widget = QTabWidget() + + # 服务器连接标签 + self.server_tab = ServerConnectionTab() + self.tab_widget.addTab(self.server_tab, "服务器连接") + + # 远程命令标签 + self.remote_tab = RemoteCommandTab(self.server_tab) + self.tab_widget.addTab(self.remote_tab, "远程命令") + + # Django标签 + self.django_tab = DjangoTab(self.server_tab) + self.tab_widget.addTab(self.django_tab, "Django") + + # Gunicorn标签 + self.gunicorn_tab = GunicornTab(self.server_tab) + self.tab_widget.addTab(self.gunicorn_tab, "Gunicorn") + + self.setCentralWidget(self.tab_widget) + + # 连接标签切换事件 + self.tab_widget.currentChanged.connect(self.on_tab_changed) + + # 设置样式 + self.setStyleSheet(""" + QMainWindow { + background-color: #f0f0f0; + } + QTabWidget::pane { + border: 1px solid #c4c4c3; + background: white; + } + QTabBar::tab { + background: #e1e1e1; + border: 1px solid #c4c4c3; + padding: 8px 16px; + margin-right: 2px; + } + QTabBar::tab:selected { + background: white; + border-bottom-color: white; + } + QPushButton { + background-color: #0078d4; + color: white; + border: none; + padding: 8px 16px; + border-radius: 4px; + font-weight: bold; + } + QPushButton:hover { + background-color: #106ebe; + } + QPushButton:pressed { + background-color: #005a9e; + } + QPushButton:disabled { + background-color: #cccccc; + color: #666666; + } + QLineEdit { + border: 1px solid #c4c4c3; + padding: 6px; + border-radius: 3px; + background-color: white; + } + QTextEdit { + border: 1px solid #c4c4c3; + background-color: #f8f8f8; + font-family: 'Consolas', 'Monaco', monospace; + } + QProgressBar { + border: 1px solid #c4c4c3; + border-radius: 3px; + text-align: center; + background-color: #f0f0f0; + } + QProgressBar::chunk { + background-color: #0078d4; + } + """) + + 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) + + +if __name__ == "__main__": + logger.add("app.log", rotation="1 day", retention="7 days") + logger.info("应用程序启动") + + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/remote_command_tab.py b/remote_command_tab.py new file mode 100644 index 0000000..9aee48b --- /dev/null +++ b/remote_command_tab.py @@ -0,0 +1,291 @@ +import os +from loguru import logger +from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, + QPushButton, QComboBox, QMessageBox, QTextEdit, + QGroupBox, QGridLayout) +from PySide6.QtCore import Qt + +from threads import (GitInstallThread, GitCloneThread, ListDirectoryThread, + DeleteDirectoryThread, SetTimezoneAndRestartThread, + CheckFirewallThread, OpenPortThread) + + +class RemoteCommandTab(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.parent = parent + self.init_ui() + + def init_ui(self): + layout = QVBoxLayout() + + # Git管理组 + git_group = QGroupBox("Git代码管理") + git_layout = QGridLayout() + + git_layout.addWidget(QLabel("Git仓库URL:"), 0, 0) + self.git_url_input = QLineEdit() + self.git_url_input.setPlaceholderText("https://github.com/username/repo.git") + git_layout.addWidget(self.git_url_input, 0, 1) + + git_layout.addWidget(QLabel("项目路径:"), 1, 0) + self.project_path_input = QLineEdit() + 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) + + self.clone_btn = QPushButton("拉取代码") + self.clone_btn.clicked.connect(self.clone_git) + git_layout.addWidget(self.clone_btn, 1, 2) + + self.list_dir_btn = QPushButton("列出目录") + 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) + + git_group.setLayout(git_layout) + layout.addWidget(git_group) + + # 防火墙管理组 + firewall_group = QGroupBox("防火墙管理") + firewall_layout = QGridLayout() + + self.check_firewall_btn = QPushButton("检查防火墙") + self.check_firewall_btn.clicked.connect(self.check_firewall) + firewall_layout.addWidget(self.check_firewall_btn, 0, 0) + + firewall_layout.addWidget(QLabel("端口:"), 0, 1) + self.port_input = QLineEdit("8000") + firewall_layout.addWidget(self.port_input, 0, 2) + + self.open_port_btn = QPushButton("开放端口") + self.open_port_btn.clicked.connect(self.open_port) + firewall_layout.addWidget(self.open_port_btn, 0, 3) + + 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() + + self.output_text = QTextEdit() + self.output_text.setReadOnly(True) + self.output_text.setPlaceholderText("操作结果将在这里显示...") + output_layout.addWidget(self.output_text) + + output_group.setLayout(output_layout) + layout.addWidget(output_group) + + layout.addStretch() + self.setLayout(layout) + + # 加载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) + + def install_git(self): + if not self.check_ssh_connection(): + return + + self.output_text.append("正在安装Git...") + self.install_git_btn.setEnabled(False) + + self.git_install_thread = GitInstallThread(self.parent.ssh_client) + self.git_install_thread.result_ready.connect(self.on_git_install_result) + self.git_install_thread.start() + + def on_git_install_result(self, success, message): + self.install_git_btn.setEnabled(True) + if success: + self.output_text.append(f"Git安装成功: {message}") + logger.info(f"Git安装成功: {message}") + else: + self.output_text.append(f"Git安装失败: {message}") + logger.error(f"Git安装失败: {message}") + + def clone_git(self): + if not self.check_ssh_connection(): + return + + git_url = self.git_url_input.text().strip() + project_path = self.project_path_input.text().strip() + + if not git_url or not project_path: + QMessageBox.warning(self, "警告", "请填写Git仓库URL和项目路径") + return + + self.output_text.append(f"正在克隆 {git_url} 到 {project_path}...") + self.clone_btn.setEnabled(False) + + self.git_clone_thread = GitCloneThread(self.parent.ssh_client, git_url, project_path) + self.git_clone_thread.result_ready.connect(self.on_git_clone_result) + self.git_clone_thread.start() + + def on_git_clone_result(self, success, message): + self.clone_btn.setEnabled(True) + if success: + self.output_text.append(f"Git克隆成功: {message}") + logger.info(f"Git克隆成功: {message}") + else: + self.output_text.append(f"Git克隆失败: {message}") + logger.error(f"Git克隆失败: {message}") + + def list_directory(self): + if not self.check_ssh_connection(): + return + + path = self.project_path_input.text().strip() + if not path: + QMessageBox.warning(self, "警告", "请输入要列出的目录路径") + return + + self.output_text.append(f"正在列出目录 {path}...") + self.list_dir_btn.setEnabled(False) + + self.list_dir_thread = ListDirectoryThread(self.parent.ssh_client, path) + self.list_dir_thread.result_ready.connect(self.on_list_directory_result) + self.list_dir_thread.start() + + def on_list_directory_result(self, success, message): + self.list_dir_btn.setEnabled(True) + if success: + self.output_text.append(f"目录列表:\n{message}") + logger.info(f"目录列表成功") + 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 + + self.output_text.append("正在设置时区为Asia/Shanghai并重启服务器...") + self.set_timezone_btn.setEnabled(False) + + self.timezone_thread = SetTimezoneAndRestartThread(self.parent.ssh_client) + self.timezone_thread.result_ready.connect(self.on_set_timezone_and_restart_result) + self.timezone_thread.start() + + def on_set_timezone_and_restart_result(self, success, message): + self.set_timezone_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 check_firewall(self): + if not self.check_ssh_connection(): + return + + self.output_text.append("正在检查防火墙状态...") + self.check_firewall_btn.setEnabled(False) + + self.firewall_thread = CheckFirewallThread(self.parent.ssh_client) + self.firewall_thread.result_ready.connect(self.on_check_firewall_result) + self.firewall_thread.start() + + def on_check_firewall_result(self, success, message): + self.check_firewall_btn.setEnabled(True) + if success: + self.output_text.append(f"防火墙状态:\n{message}") + logger.info(f"防火墙状态检查成功") + else: + self.output_text.append(f"防火墙状态检查失败: {message}") + logger.error(f"防火墙状态检查失败: {message}") + + def open_port(self): + if not self.check_ssh_connection(): + return + + port = self.port_input.text().strip() + if not port: + QMessageBox.warning(self, "警告", "请输入要开放的端口号") + return + + self.output_text.append(f"正在开放端口 {port}...") + self.open_port_btn.setEnabled(False) + + self.open_port_thread = OpenPortThread(self.parent.ssh_client, port) + self.open_port_thread.result_ready.connect(self.on_open_port_result) + self.open_port_thread.start() + + def on_open_port_result(self, success, message): + self.open_port_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 check_ssh_connection(self): + if not self.parent or not self.parent.ssh_client: + QMessageBox.warning(self, "警告", "请先连接服务器") + return False + return True \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1972069 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +PySide6>=6.5.0 +paramiko>=2.11.0 +loguru>=0.7.0 \ No newline at end of file diff --git a/server_connection_tab.py b/server_connection_tab.py new file mode 100644 index 0000000..36ab8d5 --- /dev/null +++ b/server_connection_tab.py @@ -0,0 +1,225 @@ +import json +import os +from loguru import logger +from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, + QPushButton, QComboBox, QMessageBox) +from PySide6.QtCore import Qt +import paramiko + +from threads import SSHConnectionThread + + +class ServerConnectionTab(QWidget): + def __init__(self): + super().__init__() + self.ssh_client = None + self.config = self.load_config() + self.init_ui() + + def load_config(self): + config_file = "config.json" + if os.path.exists(config_file): + try: + with open(config_file, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + logger.error(f"读取配置文件失败: {e}") + return {"servers": []} + return {"servers": []} + + def save_config(self): + try: + with open("config.json", 'w', encoding='utf-8') as f: + json.dump(self.config, f, ensure_ascii=False, indent=2) + logger.info("配置文件保存成功") + except Exception as e: + logger.error(f"保存配置文件失败: {e}") + QMessageBox.critical(self, "错误", f"保存配置文件失败: {e}") + + def init_ui(self): + layout = QVBoxLayout() + + # 服务器选择 + server_layout = QHBoxLayout() + server_layout.addWidget(QLabel("服务器别名:")) + self.server_combo = QComboBox() + self.server_combo.currentTextChanged.connect(self.on_server_selected) + server_layout.addWidget(self.server_combo) + layout.addLayout(server_layout) + + # 服务器信息输入 + form_layout = QVBoxLayout() + + # IP地址 + ip_layout = QHBoxLayout() + ip_layout.addWidget(QLabel("IP地址:")) + self.ip_input = QLineEdit() + ip_layout.addWidget(self.ip_input) + form_layout.addLayout(ip_layout) + + # 端口 + port_layout = QHBoxLayout() + port_layout.addWidget(QLabel("端口:")) + self.port_input = QLineEdit("22") + port_layout.addWidget(self.port_input) + form_layout.addLayout(port_layout) + + # 用户名 + username_layout = QHBoxLayout() + username_layout.addWidget(QLabel("用户名:")) + self.username_input = QLineEdit() + username_layout.addWidget(self.username_input) + form_layout.addLayout(username_layout) + + # 密码 + password_layout = QHBoxLayout() + password_layout.addWidget(QLabel("密码:")) + self.password_input = QLineEdit() + self.password_input.setEchoMode(QLineEdit.Password) + password_layout.addWidget(self.password_input) + form_layout.addLayout(password_layout) + + # 项目名称 + project_layout = QHBoxLayout() + project_layout.addWidget(QLabel("项目名称:")) + self.project_input = QLineEdit() + project_layout.addWidget(self.project_input) + form_layout.addLayout(project_layout) + + # Git仓库URL + git_url_layout = QHBoxLayout() + git_url_layout.addWidget(QLabel("Git仓库URL:")) + self.git_url_input = QLineEdit() + self.git_url_input.setPlaceholderText("https://github.com/username/repo.git") + git_url_layout.addWidget(self.git_url_input) + form_layout.addLayout(git_url_layout) + + # 远程目录 + remote_dir_layout = QHBoxLayout() + remote_dir_layout.addWidget(QLabel("远程目录:")) + self.remote_dir_input = QLineEdit() + self.remote_dir_input.setPlaceholderText("/home/user/project") + remote_dir_layout.addWidget(self.remote_dir_input) + form_layout.addLayout(remote_dir_layout) + + # Django项目路径 + django_path_layout = QHBoxLayout() + django_path_layout.addWidget(QLabel("Django项目路径:")) + self.django_path_input = QLineEdit() + self.django_path_input.setPlaceholderText("/home/user/django_project") + django_path_layout.addWidget(self.django_path_input) + form_layout.addLayout(django_path_layout) + + layout.addLayout(form_layout) + + # 按钮 + button_layout = QHBoxLayout() + self.save_button = QPushButton("保存配置") + self.save_button.clicked.connect(self.save_server_config) + self.connect_button = QPushButton("连接服务器") + self.connect_button.clicked.connect(self.connect_server) + button_layout.addWidget(self.save_button) + button_layout.addWidget(self.connect_button) + layout.addLayout(button_layout) + + # 连接状态 + self.status_label = QLabel("未连接") + self.status_label.setAlignment(Qt.AlignCenter) + layout.addWidget(self.status_label) + + layout.addStretch() + self.setLayout(layout) + + # 加载服务器列表 + self.load_server_list() + + def load_server_list(self): + self.server_combo.clear() + servers = self.config.get("servers", []) + for server in servers: + self.server_combo.addItem(server.get("alias", "")) + + def on_server_selected(self, alias): + if not alias: + return + + servers = self.config.get("servers", []) + for server in servers: + if server.get("alias") == alias: + self.ip_input.setText(server.get("host", "")) + self.port_input.setText(str(server.get("port", 22))) + self.username_input.setText(server.get("username", "")) + self.password_input.setText(server.get("password", "")) + self.project_input.setText(server.get("project_name", "")) + 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", "")) + break + + def save_server_config(self): + alias = self.server_combo.currentText() + if not alias: + alias = f"服务器_{len(self.config.get('servers', [])) + 1}" + self.server_combo.addItem(alias) + + server_config = { + "alias": alias, + "host": self.ip_input.text(), + "port": int(self.port_input.text()) if self.port_input.text() else 22, + "username": self.username_input.text(), + "password": self.password_input.text(), + "project_name": self.project_input.text(), + "git_url": self.git_url_input.text(), + "remote_directory": self.remote_dir_input.text(), + "django_path": self.django_path_input.text() + } + + servers = self.config.get("servers", []) + # 更新或添加服务器配置 + found = False + for i, server in enumerate(servers): + if server.get("alias") == alias: + servers[i] = server_config + found = True + break + + if not found: + servers.append(server_config) + + self.config["servers"] = servers + self.save_config() + QMessageBox.information(self, "成功", "配置已保存") + + def connect_server(self): + host = self.ip_input.text() + port = int(self.port_input.text()) if self.port_input.text() else 22 + username = self.username_input.text() + password = self.password_input.text() + + if not all([host, username, password]): + QMessageBox.warning(self, "警告", "请填写完整的连接信息") + return + + self.status_label.setText("正在连接...") + self.connect_button.setEnabled(False) + + self.connection_thread = SSHConnectionThread(host, username, password, port) + self.connection_thread.connection_status.connect(self.on_connection_result) + self.connection_thread.start() + + def on_connection_result(self, success, message): + self.connect_button.setEnabled(True) + if success: + self.status_label.setText(f"连接成功: {message}") + self.status_label.setStyleSheet("color: green;") + # 创建SSH客户端实例供其他标签使用 + self.ssh_client = paramiko.SSHClient() + self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh_client.connect(self.ip_input.text(), + port=int(self.port_input.text()), + username=self.username_input.text(), + password=self.password_input.text()) + else: + self.status_label.setText(f"连接失败: {message}") + self.status_label.setStyleSheet("color: red;") + self.ssh_client = None \ No newline at end of file diff --git a/settings_backup_20250827_194227.py b/settings_backup_20250827_194227.py new file mode 100644 index 0000000..bf307ee --- /dev/null +++ b/settings_backup_20250827_194227.py @@ -0,0 +1,113 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-$w+8+hw%p$2xi_fi+7avahc&03-y@x05e^r02-x3nt5johmk6l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'status', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'statuspage.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'statuspage.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/settings_backup_20250827_194650.py b/settings_backup_20250827_194650.py new file mode 100644 index 0000000..bf307ee --- /dev/null +++ b/settings_backup_20250827_194650.py @@ -0,0 +1,113 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-$w+8+hw%p$2xi_fi+7avahc&03-y@x05e^r02-x3nt5johmk6l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'status', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'statuspage.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'statuspage.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/settings_backup_20250827_200524.py b/settings_backup_20250827_200524.py new file mode 100644 index 0000000..bf307ee --- /dev/null +++ b/settings_backup_20250827_200524.py @@ -0,0 +1,113 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-$w+8+hw%p$2xi_fi+7avahc&03-y@x05e^r02-x3nt5johmk6l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'status', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'statuspage.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'statuspage.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/settings_backup_20250827_205200.py b/settings_backup_20250827_205200.py new file mode 100644 index 0000000..5636082 --- /dev/null +++ b/settings_backup_20250827_205200.py @@ -0,0 +1,116 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-$w+8+hw%p$2xi_fi+7avahc&03-y@x05e^r02-x3nt5johmk6l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = False + +ALLOWED_HOSTS = ["192.168.3.157"] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'status', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'statuspage.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'statuspage.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +STATIC_ROOT = BASE_DIR / "home" / "xiaji" / "static" +MEDIA_ROOT = BASE_DIR / "home" / "xiaji" / "media" diff --git a/settings_backup_20250827_211246.py b/settings_backup_20250827_211246.py new file mode 100644 index 0000000..799711a --- /dev/null +++ b/settings_backup_20250827_211246.py @@ -0,0 +1,116 @@ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-$w+8+hw%p$2xi_fi+7avahc&03-y@x05e^r02-x3nt5johmk6l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = False + +ALLOWED_HOSTS = ["192.168.3.157"] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'status', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'statuspage.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'statuspage.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +STATIC_ROOT = BASE_DIR / "static" +MEDIA_ROOT = BASE_DIR / "media" diff --git a/threads.py b/threads.py new file mode 100644 index 0000000..7507623 --- /dev/null +++ b/threads.py @@ -0,0 +1,858 @@ +import os +import time +from loguru import logger +from PySide6.QtCore import QThread, Signal +import paramiko + + +class PasswordDialog: + def __init__(self, parent=None): + self.parent = parent + self.password = None + + def get_password(self, prompt="请输入sudo密码:"): + # 这里简化实现,实际应该使用QInputDialog + if self.parent: + from PySide6.QtWidgets import QInputDialog + password, ok = QInputDialog.getText(self.parent, "sudo密码", prompt, + echo=QInputDialog.Password) + if ok: + self.password = password + return password + return None + + +class SSHConnectionThread(QThread): + connection_status = Signal(bool, str) + + def __init__(self, host, username, password, port=22): + super().__init__() + self.host = host + self.username = username + self.password = password + self.port = port + + def run(self): + try: + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(self.host, port=self.port, username=self.username, password=self.password, timeout=10) + + # 测试连接 + stdin, stdout, stderr = ssh.exec_command("echo 'Connection test'") + output = stdout.read().decode().strip() + + if output == "Connection test": + self.connection_status.emit(True, f"成功连接到 {self.host}") + logger.info(f"SSH连接成功: {self.host}") + else: + self.connection_status.emit(False, "连接测试失败") + logger.error("SSH连接测试失败") + + ssh.close() + + except Exception as e: + error_msg = str(e) + self.connection_status.emit(False, error_msg) + logger.error(f"SSH连接失败: {error_msg}") + + +class GitInstallThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client): + super().__init__() + self.ssh_client = ssh_client + + def run(self): + try: + # 检查Git是否已安装 + stdin, stdout, stderr = self.ssh_client.exec_command("git --version") + git_version = stdout.read().decode().strip() + + if git_version: + self.result_ready.emit(True, f"Git已安装: {git_version}") + logger.info(f"Git已安装: {git_version}") + return + + # 安装Git + stdin, stdout, stderr = self.ssh_client.exec_command("sudo apt update && sudo apt install -y git") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + stdin, stdout, stderr = self.ssh_client.exec_command("git --version") + git_version = stdout.read().decode().strip() + self.result_ready.emit(True, f"Git安装成功: {git_version}") + logger.info(f"Git安装成功: {git_version}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, f"Git安装失败: {error}") + logger.error(f"Git安装失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Git安装异常: {error_msg}") + + +class GitCloneThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, git_url, project_path): + super().__init__() + self.ssh_client = ssh_client + self.git_url = git_url + self.project_path = project_path + + def run(self): + try: + # 检查目录是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.project_path}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.result_ready.emit(False, f"目录 {self.project_path} 已存在") + logger.warning(f"目录已存在: {self.project_path}") + return + + # 创建父目录 + parent_dir = os.path.dirname(self.project_path) + if parent_dir: + stdin, stdout, stderr = self.ssh_client.exec_command(f"mkdir -p {parent_dir}") + + # 克隆仓库 + stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {parent_dir} && git clone {self.git_url} {os.path.basename(self.project_path)}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.result_ready.emit(True, f"Git克隆成功: {self.project_path}") + logger.info(f"Git克隆成功: {self.project_path}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, f"Git克隆失败: {error}") + logger.error(f"Git克隆失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Git克隆异常: {error_msg}") + + +class ListDirectoryThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, path): + super().__init__() + self.ssh_client = ssh_client + self.path = path + + def run(self): + try: + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.path}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + output = stdout.read().decode() + self.result_ready.emit(True, output) + logger.info(f"目录列表成功: {self.path}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"目录列表失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"目录列表异常: {error_msg}") + + +class DeleteDirectoryThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, path): + super().__init__() + self.ssh_client = ssh_client + self.path = path + + def run(self): + try: + stdin, stdout, stderr = self.ssh_client.exec_command(f"rm -rf {self.path}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.result_ready.emit(True, f"目录删除成功: {self.path}") + logger.info(f"目录删除成功: {self.path}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"目录删除失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"目录删除异常: {error_msg}") + + +class SetTimezoneAndRestartThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client): + super().__init__() + self.ssh_client = ssh_client + + def run(self): + try: + # 设置时区 + stdin, stdout, stderr = self.ssh_client.exec_command("sudo timedatectl set-timezone Asia/Shanghai") + 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 + + # 重启服务器 + stdin, stdout, stderr = self.ssh_client.exec_command("sudo reboot") + + self.result_ready.emit(True, "时区设置成功,服务器正在重启") + logger.info("时区设置成功,服务器正在重启") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"时区设置异常: {error_msg}") + + +class CheckFirewallThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client): + super().__init__() + self.ssh_client = ssh_client + + def run(self): + try: + # 检查UFW状态 + stdin, stdout, stderr = self.ssh_client.exec_command("sudo ufw status") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + output = stdout.read().decode() + self.result_ready.emit(True, output) + logger.info("防火墙状态检查成功") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"防火墙状态检查失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"防火墙状态检查异常: {error_msg}") + + +class OpenPortThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, port): + super().__init__() + self.ssh_client = ssh_client + self.port = port + + def run(self): + try: + # 开放端口 + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo ufw allow {self.port}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + # 重新加载防火墙 + stdin, stdout, stderr = self.ssh_client.exec_command("sudo ufw reload") + + self.result_ready.emit(True, f"端口 {self.port} 开放成功") + logger.info(f"端口 {self.port} 开放成功") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"端口开放失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"端口开放异常: {error_msg}") + + +class DjangoInstallThread(QThread): + result_ready = Signal(bool, str) + progress_updated = Signal(int) + + def __init__(self, ssh_client): + super().__init__() + self.ssh_client = ssh_client + + def run(self): + try: + self.progress_updated.emit(10) + + # 检查Django是否已安装 + stdin, stdout, stderr = self.ssh_client.exec_command("python3 -m django --version") + django_version = stdout.read().decode().strip() + + if django_version: + self.result_ready.emit(True, f"Django已安装: {django_version}") + logger.info(f"Django已安装: {django_version}") + return + + self.progress_updated.emit(30) + + # 尝试使用pip安装 + stdin, stdout, stderr = self.ssh_client.exec_command("pip3 install django") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.progress_updated.emit(90) + stdin, stdout, stderr = self.ssh_client.exec_command("python3 -m django --version") + django_version = stdout.read().decode().strip() + self.result_ready.emit(True, f"Django安装成功: {django_version}") + logger.info(f"Django安装成功: {django_version}") + return + + self.progress_updated.emit(50) + + # 如果pip安装失败,尝试使用apt安装 + stdin, stdout, stderr = self.ssh_client.exec_command("sudo apt update && sudo apt install -y python3-django") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.progress_updated.emit(90) + stdin, stdout, stderr = self.ssh_client.exec_command("python3 -m django --version") + django_version = stdout.read().decode().strip() + self.result_ready.emit(True, f"Django安装成功: {django_version}") + logger.info(f"Django安装成功: {django_version}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, f"Django安装失败: {error}") + logger.error(f"Django安装失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Django安装异常: {error_msg}") + + +class DjangoTestThread(QThread): + result_ready = Signal(bool, str) + progress_updated = Signal(int) + + def __init__(self, ssh_client, django_path): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + + def run(self): + try: + self.progress_updated.emit(10) + + # 检查Django项目是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/manage.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, f"Django项目不存在: {self.django_path}") + logger.error(f"Django项目不存在: {self.django_path}") + return + + self.progress_updated.emit(30) + + # 检查requirements.txt + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/requirements.txt") + exit_status = stdout.channel.recv_exit_status() + + 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") + 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 + + 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 &") + time.sleep(3) # 等待服务器启动 + + # 检查服务器是否运行 + stdin, stdout, stderr = self.ssh_client.exec_command("ps aux | grep 'manage.py runserver'") + output = stdout.read().decode() + + if "manage.py runserver" in output: + self.progress_updated.emit(100) + self.result_ready.emit(True, "Django测试服务器启动成功") + logger.info("Django测试服务器启动成功") + else: + self.result_ready.emit(False, "Django测试服务器启动失败") + logger.error("Django测试服务器启动失败") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Django测试异常: {error_msg}") + + +class DownloadSettingsThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, django_path): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + + def run(self): + try: + # 查找settings.py文件 + stdin, stdout, stderr = self.ssh_client.exec_command(f"find {self.django_path} -name settings.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, "未找到settings.py文件") + logger.error("未找到settings.py文件") + return + + settings_path = stdout.read().decode().strip() + + # 下载settings.py内容 + stdin, stdout, stderr = self.ssh_client.exec_command(f"cat {settings_path}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + settings_content = stdout.read().decode() + self.result_ready.emit(True, settings_content) + logger.info("settings.py下载成功") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"settings.py下载失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"settings.py下载异常: {error_msg}") + + +class UploadSettingsThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, django_path, settings_content): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + self.settings_content = settings_content + + def run(self): + try: + # 查找settings.py文件 + stdin, stdout, stderr = self.ssh_client.exec_command(f"find {self.django_path} -name settings.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, "未找到settings.py文件") + logger.error("未找到settings.py文件") + return + + settings_path = stdout.read().decode().strip() + + # 创建临时文件 + temp_file = "/tmp/settings_upload.py" + sftp = self.ssh_client.open_sftp() + + with sftp.file(temp_file, 'w') as f: + f.write(self.settings_content) + + # 移动到目标位置 + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo mv {temp_file} {settings_path}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.result_ready.emit(True, "settings.py上传成功") + logger.info("settings.py上传成功") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"settings.py上传失败: {error}") + + sftp.close() + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"settings.py上传异常: {error_msg}") + + +class CollectStaticThread(QThread): + result_ready = Signal(bool, str) + progress_updated = Signal(int) + + def __init__(self, ssh_client, django_path): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + + def run(self): + try: + self.progress_updated.emit(10) + + # 检查Django项目是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/manage.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, f"Django项目不存在: {self.django_path}") + logger.error(f"Django项目不存在: {self.django_path}") + return + + self.progress_updated.emit(30) + + # 收集静态文件 + stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && python3 manage.py collectstatic --noinput") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.progress_updated.emit(100) + output = stdout.read().decode() + self.result_ready.emit(True, f"静态文件收集成功: {output}") + logger.info("静态文件收集成功") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"静态文件收集失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"静态文件收集异常: {error_msg}") + + +class CheckDjangoStatusThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, django_path): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + + def run(self): + try: + status_info = [] + + # 检查Django项目是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/manage.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, f"Django项目不存在: {self.django_path}") + logger.error(f"Django项目不存在: {self.django_path}") + return + + status_info.append("✓ Django项目存在") + + # 检查Django版本 + stdin, stdout, stderr = self.ssh_client.exec_command("python3 -m django --version") + django_version = stdout.read().decode().strip() + status_info.append(f"✓ Django版本: {django_version}") + + # 检查requirements.txt + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/requirements.txt") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + status_info.append("✓ requirements.txt存在") + else: + status_info.append("✗ requirements.txt不存在") + + # 检查settings.py + stdin, stdout, stderr = self.ssh_client.exec_command(f"find {self.django_path} -name settings.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + status_info.append("✓ settings.py存在") + else: + status_info.append("✗ settings.py不存在") + + # 检查静态文件目录 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/static") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + status_info.append("✓ static目录存在") + else: + status_info.append("✗ static目录不存在") + + status_text = "\n".join(status_info) + self.result_ready.emit(True, status_text) + logger.info("Django状态检查完成") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Django状态检查异常: {error_msg}") + + +class GunicornInstallThread(QThread): + result_ready = Signal(bool, str) + progress_updated = Signal(int) + + def __init__(self, ssh_client, password=None): + super().__init__() + self.ssh_client = ssh_client + self.password = password + + def run(self): + try: + self.progress_updated.emit(10) + + # 检查Gunicorn是否已安装 + stdin, stdout, stderr = self.ssh_client.exec_command("gunicorn --version") + gunicorn_version = stdout.read().decode().strip() + + if gunicorn_version: + self.result_ready.emit(True, f"Gunicorn已安装: {gunicorn_version}") + logger.info(f"Gunicorn已安装: {gunicorn_version}") + return + + self.progress_updated.emit(30) + + # 尝试使用pip安装 + stdin, stdout, stderr = self.ssh_client.exec_command("pip3 install gunicorn") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.progress_updated.emit(90) + stdin, stdout, stderr = self.ssh_client.exec_command("gunicorn --version") + gunicorn_version = stdout.read().decode().strip() + self.result_ready.emit(True, f"Gunicorn安装成功: {gunicorn_version}") + logger.info(f"Gunicorn安装成功: {gunicorn_version}") + return + + self.progress_updated.emit(50) + + # 如果pip安装失败,尝试使用apt安装 + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command("sudo -S apt update && sudo -S apt install -y gunicorn") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command("sudo apt update && sudo apt install -y gunicorn") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + self.progress_updated.emit(90) + stdin, stdout, stderr = self.ssh_client.exec_command("gunicorn --version") + gunicorn_version = stdout.read().decode().strip() + self.result_ready.emit(True, f"Gunicorn安装成功: {gunicorn_version}") + logger.info(f"Gunicorn安装成功: {gunicorn_version}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, f"Gunicorn安装失败: {error}") + logger.error(f"Gunicorn安装失败: {error}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Gunicorn安装异常: {error_msg}") + + +class GunicornTestThread(QThread): + result_ready = Signal(bool, str) + progress_updated = Signal(int) + + def __init__(self, ssh_client, django_path): + super().__init__() + self.ssh_client = ssh_client + self.django_path = django_path + + def run(self): + try: + self.progress_updated.emit(10) + + # 检查Django项目是否存在 + stdin, stdout, stderr = self.ssh_client.exec_command(f"ls -la {self.django_path}/manage.py") + exit_status = stdout.channel.recv_exit_status() + + if exit_status != 0: + self.result_ready.emit(False, f"Django项目不存在: {self.django_path}") + logger.error(f"Django项目不存在: {self.django_path}") + return + + 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" + 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 + + self.progress_updated.emit(50) + + # 测试Gunicorn启动 + stdin, stdout, stderr = self.ssh_client.exec_command(f"cd {self.django_path} && gunicorn --workers 2 --bind 0.0.0.0:8001 {project_name}.wsgi:application --timeout 10 &") + time.sleep(5) # 等待Gunicorn启动 + + # 检查Gunicorn是否运行 + stdin, stdout, stderr = self.ssh_client.exec_command("ps aux | grep gunicorn") + output = stdout.read().decode() + + if "gunicorn" in output and "--bind 0.0.0.0:8001" in output: + # 停止测试进程 + stdin, stdout, stderr = self.ssh_client.exec_command("pkill -f 'gunicorn --bind 0.0.0.0:8001'") + + self.progress_updated.emit(100) + self.result_ready.emit(True, "Gunicorn测试成功") + logger.info("Gunicorn测试成功") + else: + self.result_ready.emit(False, "Gunicorn测试失败") + logger.error("Gunicorn测试失败") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"Gunicorn测试异常: {error_msg}") + + +class UploadGunicornServiceThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, service_name, service_content, password=None): + super().__init__() + self.ssh_client = ssh_client + self.service_name = service_name + self.service_content = service_content + self.password = password + + def run(self): + try: + # 创建服务文件 + service_file = f"/etc/systemd/system/{self.service_name}.service" + temp_file = f"/tmp/{self.service_name}.service" + + sftp = self.ssh_client.open_sftp() + + with sftp.file(temp_file, 'w') as f: + f.write(self.service_content) + + # 移动到systemd目录 + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S mv {temp_file} {service_file}") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo mv {temp_file} {service_file}") + 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}") + sftp.close() + return + + # 设置权限 + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S chmod 644 {service_file}") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo chmod 644 {service_file}") + 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}") + sftp.close() + return + + # 重新加载systemd + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command("sudo -S systemctl daemon-reload") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command("sudo systemctl daemon-reload") + + sftp.close() + + self.result_ready.emit(True, f"服务文件上传成功: {service_file}") + logger.info(f"服务文件上传成功: {service_file}") + + except Exception as e: + error_msg = str(e) + self.result_ready.emit(False, error_msg) + logger.error(f"服务文件上传异常: {error_msg}") + + +class ManageGunicornServiceThread(QThread): + result_ready = Signal(bool, str) + + def __init__(self, ssh_client, service_name, action, password=None): + super().__init__() + self.ssh_client = ssh_client + self.service_name = service_name + self.action = action + self.password = password + + def run(self): + try: + # 构建systemd命令 + cmd = f"systemctl {self.action} {self.service_name}" + + if self.action == "status": + # 状态命令需要特殊处理 + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S {cmd}") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo {cmd}") + exit_status = stdout.channel.recv_exit_status() + + if exit_status == 0: + output = stdout.read().decode() + 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}") + else: + # 其他操作(start, stop, restart, enable, disable) + if self.password: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo -S {cmd}") + stdin.write(f"{self.password}\n") + stdin.flush() + else: + stdin, stdout, stderr = self.ssh_client.exec_command(f"sudo {cmd}") + 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}") + else: + error = stderr.read().decode() + self.result_ready.emit(False, error) + logger.error(f"服务{self.action}失败: {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