1 背景
最近,某模块调用ansible执行任务的时候,出现无任何出错打印,误判执行成功,但实际执行失败的情况。
排查下来只由于代码里面既没有处理命令的返回值,也没有处理错误输出,仅通过标准输出里面的错误打印来判断成功失败,标准输出里面的错误打印其实是仅在命令本身执行成功的情况下才会有输出的,这种判断方法很有可能导致误判命令执行成功。
而且一旦失败,对错误的定位非常不利。
为了防止其他模块当前的各种python代码执行操作系统命令的时候出现类似情况,特拟制本说明。
2 典型错误
2.1 直接使用os.popen创建,但不处理返回的错误码
后果:
2.1.1 对只有错误打印的,调用者会误判执行成功了
2.1.2 如果调用命令挂死,会导致主进程挂死
2.2 使用subprocess.popen创建,要么没有定义stderr,要么定义了,没有从stderr读信息,也没有处理返回码
后果:
2.2.1 stderr满的情况下,主进程挂死
2.2.2 和os.popen类似,对只有错误打印输出的命令调用,会误判执行成功了
3 推荐用法
3.1 对命令执行时间没有限制,或者认为肯定不会挂住,并且不关心错误输出的用这个(一般情况下不建议使用):
def test_os_popen_func(cmd):
stdout, proc = os.popen(cmd)
if proc.close:
return false, ""
return true, stdout.read()
3.2 对命令执行时间有限制,或者认为命令有可能挂住,或者关心命令的错误输出的情况下用这个,默认超时时间15秒:
def test_subprocess_popen_func(cmd, timeout=15):
proc = subprocess.popen(cmd, stdout=PIPE, stderr=PIPE)
retruncode = 0xff
try:
outs, errs = proc.communicate(timeout=timeout)
retruncode = proc.poll()
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
return retruncode, outs, errs
上面列的这些错误调用方法,在python的标准库和部分开源库(例如非常有名的ansible)中非常常见,只能说明很多python程序员都只关注程序执行成功的时候代码怎么写,执行失败的情况,处于无人关注的状态,这对生产环境下的使用是非常不利的。