Django应用如何在网页展示远程SSH命令执行结果?
问题描述
我有一个简单的Django应用,用于展示远程SSH命令的执行结果。相关代码如下:
views.py
from django.http import HttpResponse from subprocess import * def index(request): with open('/home/python/django/cron/sites.txt', 'r') as file: for site in file: # out = getoutput(f"ssh -o StrictHostKeyChecking=accept-new -p1994 root@{site} crontab -l") out = run(["ssh", "-o StrictHostKeyChecking=accept-new", "-p1994", f"root@{site}".strip(), "crontab", "-l"]) return HttpResponse(out)
urls.py
from django.contrib import admin from django.urls import path # imported views from cron import views urlpatterns = [ path('admin/', admin.site.urls), # configured the url path('',views.index, name="homepage") ]
sites.txt
1.1.1.1 2.2.2.2 3.3.3.3
访问localhost:5000时,页面仅显示CompletedProcess对象信息,而非预期的crontab命令执行结果。尝试过run和getoutput方法,但要么无法建立连接,要么输出仅显示在终端中。如何实现并在网页中展示正确的执行结果?
解决方案
核心问题分析
subprocess.run()默认不捕获命令输出,返回的是CompletedProcess对象,直接返回给HttpResponse会显示对象的字符串表示,而非命令结果。- 循环中每次迭代都会覆盖
out变量,最终仅返回最后一台主机的结果。 - SSH连接可能因为缺少免密配置导致交互阻塞,或输出未被正确捕获。
修改后的代码实现
推荐使用subprocess.run()并显式捕获输出,同时收集所有主机的结果:
from django.http import HttpResponse from subprocess import run, PIPE def index(request): results = [] with open('/home/python/django/cron/sites.txt', 'r') as file: for site in file: site = site.strip() if not site: continue # 跳过空行,避免无效连接 # 执行SSH命令,捕获标准输出与错误 cmd_result = run( ["ssh", "-o", "StrictHostKeyChecking=accept-new", "-p1994", f"root@{site}", "crontab", "-l"], stdout=PIPE, stderr=PIPE, text=True # 让输出以字符串形式返回,而非字节流 ) # 整理单台主机的结果内容 host_content = f"<h3>主机 {site} 的Crontab信息</h3>" if cmd_result.returncode == 0: host_content += f"<pre>{cmd_result.stdout}</pre>" else: host_content += f"<p style='color:red;'>执行失败:{cmd_result.stderr}</p>" results.append(host_content) # 将所有结果拼接为HTML返回,确保页面展示清晰 return HttpResponse("<br>".join(results))
关键修改点说明
- 用
results列表存储每台主机的结果,避免循环覆盖问题。 - 通过
stdout=PIPE和stderr=PIPE捕获命令的输出与错误信息,text=True简化字节流转字符串的操作。 - 根据命令返回码判断执行状态,成功时展示Crontab内容,失败时显示错误信息,用HTML标签优化页面可读性。
- 跳过文件中的空行,避免无效的SSH连接尝试。
可选:使用getoutput的简化实现
如果不需要判断命令执行状态,可使用getoutput(它会合并标准输出与错误):
from django.http import HttpResponse from subprocess import getoutput def index(request): results = [] with open('/home/python/django/cron/sites.txt', 'r') as file: for site in file: site = site.strip() if not site: continue output = getoutput(f"ssh -o StrictHostKeyChecking=accept-new -p1994 root@{site} crontab -l") results.append(f"<h3>主机 {site}</h3><pre>{output}</pre>") return HttpResponse("<br>".join(results))
必做的前置配置
确保运行Django的用户(如服务器的www-data或本地登录用户)已配置免密SSH登录到所有远程主机,否则SSH会要求输入密码导致命令阻塞。配置命令示例:
ssh-copy-id -p1994 root@1.1.1.1
内容的提问来源于stack exchange,提问作者Saeed
相关产品推荐
相关产品推荐

