我在使用Python中的Thread中的subprocess.Popen()调用脚本时遇到问题。我尽可能多地添加了细节。如果我需要在问题中添加更多详细信息,请告知我们。任何帮助是极大的赞赏。提前致谢。
TL:DR subprocess.Popen()期待stdin并抛出错误" tandard in必须是tty"即使调用的脚本不需要任何标准输入。这个问题从" su userName -c"开始出现。已在调用脚本时使用
详情
我正在使用django开发一个Web应用程序,它在后端执行PERL脚本。我正在以root用户身份部署应用程序,我打算以触发它的用户身份运行脚本。我将从我们页面中的用户那里获取userName。
初始命令测试:我以root身份登录,我使用以下命令以用户身份启动脚本:
su userName -c ' /path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000'
以上工作正常,并按照用户在以root用户身份登录的终端中调用时指定的方式运行。所以我理解上面的命令没有问题。
工作流程
当用户提供输入并在网页中提交输入时,我启动一个守护程序线程,在后台调用上述命令。一旦调用该命令,perl脚本就完成其任务并返回结果。
我在views.py中使用以下代码创建一个线程(注意:我只编写与问题相关的代码行而不是views.py的完整内容)
from threading import Thread
reImageThread = Thread(name = hostName, target = reImageFunction ,args = (hostName,buildNumber,userName) )
reImageThread.daemon = True
reImageThread.start()
reImageFunction在另一个文件中定义如下:
import subprocess
def reImageFunction(hostName,buildNumber,userName):
command = " /path_to_my_script/reImage.pm --host "+str(hostName)+" --version "+str(buildNumber)+" " #Blank space at the end is added intentionally
command = " su " + userName + " -c \' " + command + " \' "
print(command) #printing for debugging
#The final command composed would of the format shown in the begenning of this question.
pipe = subprocess.Popen(command , stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
(result,err) = pipe.communicate()
print(err) #Printing the err for debugging
.... #Processing the result
.... #Processing the result
错误:b'标准必须是tty \ n'在pipe.communicate()
被抛出我已经明确提到stdin将是None。但我不明白为什么子进程仍然需要一些输入。
观察:
当我删除" su用户名-c"上面的命令是通过子进程执行的,没有任何问题。部分,示例如下所示。但这不是预期的功能,所以我必须以触发它的用户身份运行它。
没有" su userName -c&#34的示例命令;部分:
/path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000
问题开始出现,因为" su userName -c"已被添加。
我尝试了以下内容:
谢谢你的耐心和阅读,直到最后,
答案 0 :(得分:0)
我找到了解决问题的方法。
最初,当我尝试使用终端中的以下内容时,
sudo -u userName command
我无法执行,因为我遇到了“权限被拒绝”错误。所以后来我开始使用终端
中的以下命令su userName -c "command"
这个su命令在终端上运行良好。现在是时候在我的Web应用程序中使用它来通过 subprocess.invoke(command)在系统上调用此命令,这就是我得到“标准必须是tty”错误的地方。
我在注释中跟随了@Ryan给出的链接,并在/ etc / sudoers文件中更改了root用户的requiretty,如下所示,这也无济于事。
Defaults:root !requiretty
最后,当我评论“默认值:requiretty”时(我知道这可能会引起安全问题,但对于这个应用程序来说会很好)并在子进程中使用 su -userName命令。 invoke(),它按预期工作。现在我能够以请求的用户身份运行脚本。
感谢阅读,