![如何让 salt 执行模块在失败时返回非零退出代码](https://linux22.com/image/698566/%E5%A6%82%E4%BD%95%E8%AE%A9%20salt%20%E6%89%A7%E8%A1%8C%E6%A8%A1%E5%9D%97%E5%9C%A8%E5%A4%B1%E8%B4%A5%E6%97%B6%E8%BF%94%E5%9B%9E%E9%9D%9E%E9%9B%B6%E9%80%80%E5%87%BA%E4%BB%A3%E7%A0%81.png)
我正在尝试使用 Jenkins 运行 Salt 执行模块命令;如果任何 minion 无法执行该命令,我希望 Jenkins 作业失败。Jenkins 只是遵循一般的 shell 脚本编写实践,即在非零退出代码时失败,因此要使其正常工作,Salt 也应该如此。
这就是我被困住的地方,运行这样的操作可以按预期工作:
root@salt-master:~# salt --batch-size 1 --failhard -G 'ec2_roles:stage' cmd.run 'exit 0'
Executing run on ['stage-12']
jid:
20170209212325270060
retcode:
0
stage-12:
Executing run on ['stage-13']
jid:
20170209212325423735
retcode:
0
stage-13:
Executing run on ['stage-197']
jid:
20170209212325590982
retcode:
0
stage-197:
root@salt-master:~# echo $?
0
root@salt-master:~# salt --batch-size 1 --failhard -G 'ec2_roles:stage' cmd.run 'exit 1'
Executing run on ['stage-12']
{'stage-12': {'jid': '20170209212334018054', 'retcode': 1, 'ret': ''}}
ERROR: Minions returned with non-zero exit code.
root@salt-master:~# echo $?
1
但是当我尝试运行类似以下测试的执行模块时:
# mymodule.py
from salt.exceptions import CommandExecutionError
def testfailure():
raise CommandExecutionError('fail!')
我得到以下结果:
root@salt-master:~# salt --batch-size 1 --failhard -G 'ec2_roles:stage' mymodule.testfailure
Executing run on ['stage-12']
jid:
20170210023059009796
stage-12:
ERROR: fail!
Executing run on ['stage-13']
jid:
20170210023059179183
stage-13:
ERROR: fail!
Executing run on ['stage-197']
jid:
20170210023059426845
stage-197:
ERROR: fail!
root@salt-master:~# echo $?
0
答案1
我不确定您如何处理模块中的错误,但无论如何,我想对此进行一些说明。
有一本 dunder 词典__context__
。当您运行执行模块时,__context__
字典会在所有模块执行中持续存在,直到模块刷新为止。状态模块的行为类似。字典可以包含一个键,'retcode'
该键似乎引用了 salt minion/client 应该返回的返回代码,而您却遗漏了该代码。
我看到它在一些执行模块中使用。一个例子来自nspawn模块:
def _make_container_root(name):
'''
Make the container root directory
'''
path = _root(name)
if os.path.exists(path):
__context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL
raise CommandExecutionError(
'Container {0} already exists'.format(name)
)
else:
try:
os.makedirs(path)
return path
except OSError as exc:
raise CommandExecutionError(
'Unable to make container root directory {0}: {1}'
.format(name, exc)
现在说说不好的地方。我在旧的 SaltStack 2015.8.12 上测试了它,它以某种方式工作,但没有使用异常:
def testfailure():
__context__['retcode'] = 1
执行模块返回高于以下的错误代码0
:
salt my_minion mymodule.testfailure; echo $?
my_minion:
None
ERROR: Minions returned with non-zero exit code
11
当你引发异常时,它会停止工作并且总是返回0
。
# mymodule.py
from salt.exceptions import CommandExecutionError
def testfailure():
__context__['retcode'] = 1
raise CommandExecutionError('fail')
执行模块返回错误代码,尽管0
它不应该:
salt my_minion mymodule.testfailure; echo $?
my_minion:
ERROR: fail!
0
我也在最新版本 2016.11.3 上测试了它,行为是一样的。在我看来,这是一个错误。我报告了它这里。
答案2
据我所知,退出代码是 Salt 的一个常见问题。他们的 Github 错误跟踪器中有一组与此问题相关的票据。我见过的查找 salt 状态是否成功应用的最佳方法是盐厨房简而言之,这只是 salt 命令的一个简单包装器,用于 grep 特定消息的输出。grep 命令如下:
grep -e Result.*False -e Data.failed.to.compile -e No.matching.sls.found.for
在您的例子中,您还可以在 string 上添加 match ERROR:
。您可能还需要反转 grep 的退出代码,就像0
找到匹配项时一样。您可以使用一个简单的技巧来做到这一点,在这个问题。因此最终你的 salt 命令可能看起来像这样:
salt <your options go here> | tee grep -q -e Result.*False -e Data.failed.to.compile -e No.matching.sls.found.for -e ERROR: ; test $? -eq 1
这将显示 salt 的完整输出,抑制 grep 输出并返回 grep 的反向返回码,表示1
是否发现任何错误消息,0
如果没有。
答案3
对于仍在尝试解决此问题的人,您可以执行以下操作:
salt * state.highstate --retcode-passthrough
或者
salt-call * state.highstate --retcode-passthrough