如何让 salt 执行模块在失败时返回非零退出代码

如何让 salt 执行模块在失败时返回非零退出代码

我正在尝试使用 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

相关内容