使用subprocess.communicate()的线程会抛出错误:b'标准必须是tty \\ n'

时间:2017-03-15 02:12:34

标签: python python-2.7 python-3.x django-views subprocess

我在使用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。但我不明白为什么子进程仍然需要一些输入。

观察:

  1. 问题出现在我尝试使用子进程 [pipe.communicate()]并运行上述命令的地方。
  2. 当我删除" su用户名-c"上面的命令是通过子进程执行的,没有任何问题。部分,示例如下所示。但这不是预期的功能,所以我必须以触发它的用户身份运行它。

    没有" su userName -c&#34的示​​例命令;部分:

    /path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000

  3. 问题开始出现,因为" su userName -c"已被添加。

  4. 我已经知道子进程正在期待stdin,因此即使不调用命令也会抛出错误。
  5. 当我从终端运行它时,脚本以指定用户身份运行而不接受/提示输入/ stdin。一旦调用它就不需要任何stdin但是我不明白为什么subprocess.communicate()期望我提供输入。
  6. 我尝试了以下内容:

    1. 我在pipe.communicate()没有输入的情况下尝试过相同的功能,但是它会抛出相同的错误。
    2. 我尝试过stdin = subprocess.PIPE和pipe.communicate(输入=' \ n')。我试图将新行作为标准输入,但它会抛出相同的错误。
    3. 尝试使用subprocess.call(),即使抛出相同的错误。
    4. 无法使用os.system(命令),因为我需要分析输出。如果subprocess.Popen()根本不起作用,则将输出写入文件可能是一种解决方法。
    5. 谢谢你的耐心和阅读,直到最后,

1 个答案:

答案 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(),它按预期工作。现在我能够以请求的用户身份运行脚本。

感谢阅读,