Jenkins没有在控制台中打印Python脚本的输出

11

我有一个Python脚本(myscript.py),其内容如下:

#!/bin/python
import os
import optparse
import subprocess
import sys
sys.stdout.flush()

print("I can see this message on Jenkins console output")
cmd="sshpass -p 'xxx' ssh test@testmachine 'cmd /c cd C:\stage && test.bat'"
retval=subprocess.call(cmd,shell=True)
print retval

在Jenkins中,我有一个任务,其中的执行脚本如下:

#!/bin/sh
./myscript.py
问题: Jenkins控制台仅显示"I can see this message on Jenkins console output"。如果从子进程调用中有任何输出,它不会在控制台上打印出来。
如果我通过putty连接到服务器A,并在shell上运行相同的命令(./myscript.py),我可以看到子进程调用的输出。
如何将这个子进程调用的输出打印在Jenkins控制台上?
FYI: 如您所见,我的命令从Windows上运行一个批处理文件;Jenkins正在运行Linux;两台机器之间有ssh设置。 编辑: 我的test.bat看起来像这样:

echo off
RMDIR /S /Q C:\Test

IF %ERRORLEVEL% NEQ 0 (
  ECHO Could not delete
  EXIT /b %ERRORLEVEL%
)
如果我在Windows服务器上本地运行此批处理文件,它会返回1(因为我正在Test文件夹中持有一个文件)。但是当Python脚本使用subprocess调用此批处理文件时,我得到的只是0作为返回值。为什么会这样,怎么解决?如果我能捕获正确的返回值,我就可以使Jenkins任务失败。编辑12/12:你好!有人能帮忙吗?

3
我怀疑你的问题出在使用sshpass上。它会建立自己的tty以欺骗ssh允许交互式会话。它还根据连接的成功与否设置返回代码,而不是ssh内部运行命令的结果。你可以尝试直接使用ssh,并授权使用公钥吗? - Peter Brittain
好的,我现在会尝试翻译。 - user1164061
没用!我创建了一个公钥并且摆脱了ssh密码.. 但是我仍然得到相同的结果... :-( - user1164061
如果那样做不能解决问题,我能想到的唯一解释是你遇到了Windows中的这个bug:https://dev59.com/questions/YGgu5IYBdhLWcg3ws5FC - Peter Brittain
太棒了!我现在已经写出答案了。 - Peter Brittain
显示剩余3条评论
4个回答

14

我想知道这是否与stdout被缓冲有关。 您可以尝试在运行命令之前设置PYTHONUNBUFFERED吗?

export PYTHONUNBUFFERED=true

这会影响所有的Python打印吗? - undefined

10
在我的Jenkins环境中,使用不带缓冲参数的Python脚本可以使输出立即显示。就像这样:
python3 -u some_script.py

更多信息可以通过帮助菜单(python3 --help)获取:

-u     : force the stdout and stderr streams to be unbuffered;
         this option has no effect on stdin; also PYTHONUNBUFFERED=x

1
谢谢,添加了这个参数后,一切都按预期工作。 - Lancer.Yan

3

TL; DR

解决方法是在rmdir上使用一些条件执行(||运算符)来修复返回的错误级别。

调查

这是一个非常棘手的错误,经历了许多曲折! 最初我们怀疑标准输出链的某些部分出了问题,因此通过在Popen中显式使用管道以及将sshpass从您的命令中移除并直接使用ssh的输出来进行研究。

然而,这没有解决问题,所以我们开始检查命令的返回代码。 在删除sshpass后,ssh应返回运行的命令的结果。 然而,这对于您始终是0。

此时,我发现Windows中已知的一个错误是rmdir(与rd相同)不总是正确地设置errorlevel。 解决方法是在rmdir上使用一些条件执行(||运算符)来修复错误级别。

有关详细信息,请参见batch: Exit code for "rd" is 0 on error as well


再次感谢您! - user1164061
对于其他遇到相同问题的人:RMDIR /S /Q C:\Test && echo success || echo failure 可以正常工作,即它返回一个错误级别,但是 RMDIR /S /Q C:\Test &&echo success || echo %ERRORLEVEL% 不会回显错误级别... 它必须在下一行代码中。 - user1164061

3
当你在shell中执行脚本时,Python会将你的shell的STDOUT设置为子进程的STDOUT,因此所有被执行的内容都会被打印到终端上。但是,在Jenkins中执行时,子进程没有继承shell的STDOUT,因此其输出不会显示。
很可能解决问题的最好方法是将STDOUT(和STDERR)传输并在进程结束后打印出来。此外,如果你以子进程的退出代码退出,并且退出代码不是0,它可能会终止你的Jenkins作业。
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE, shell=True)
exit_code = p.wait()  # wait for it to end
print('Got the following output from the script:\n', p.stdout.read().decode())
print('Got the following errors from the script:\n', p.stderr.read().decode())
print('Script returned exit code:', exit_code)

sys.exit(exit_code)

谢谢你的帮助。但这仍然没有解决问题。我在C:\Test中打开了一个文本文件;所以我的test.bat应该返回1。但是我得到的是:('Got the following errors from the script:\n', u'')('Script returned exit code:', 0) - user1164061
@slav - 基于您的专业知识,有什么建议吗? - user1164061
我已经在C:\Test中打开了一个文本文件; 因此,我的test.bat应该返回1,但这并没有说明太多。 在某些环境下,只要是读取或甚至写入,就可以多次打开同一文件。 https://dev59.com/IX3aa4cB1Zd3GeqPg7ex#22469791根据我所知,billy的代码似乎是正确的。如果它没有返回1,则表示它没有出现错误。 - Nande
https://dev59.com/SGUq5IYBdhLWcg3waP3r Python 上的多次读取 - Nande

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接