Я пытаюсь использовать Jenkins для запуска команды модуля выполнения Salt; если какой-либо миньон не может выполнить команду, я хочу, чтобы задание Дженкинса завершилось неудачей. Дженкинс просто следует общей практике сценариев оболочки - сбой при ненулевом коде выхода, поэтому, чтобы заставить его работать, 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
Я не уверен, как вы обрабатываете ошибки в своем модуле, но в любом случае я хотел бы пролить свет на это.
Доступен dunder словарь __context__
. Когда вы запускаете модуль выполнения, __context__
словарь сохраняется при выполнении всех модулей, пока модули не будут обновлены. Модули состояний ведут себя аналогично. В словаре можно найти ключ 'retcode'
который, кажется, относится к коду возврата, который должен вернуть миньон / клиент, и который вам не хватает.
Я вижу, что он используется в некоторых исполнительных модулях. Один пример из 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, и поведение было таким же. ИМО, это ошибка. Я сообщил об этом Вот.
Коды выхода AFAIK - это общая проблема с Salt. В их трекере ошибок Github есть набор билетов по этой проблеме. Лучший способ узнать, применялись ли солевые состояния успешно или нет, - это тот, который использовал соляная кухня. Вкратце, есть просто простая оболочка вокруг команды salt, которая выводит grep для конкретных сообщений. Команда grep следующая:
grep -e Result.*False -e Data.failed.to.compile -e No.matching.sls.found.for
В вашем случае вы также можете добавить совпадение в строку ERROR:
. Вам также, вероятно, потребуется инвертировать код выхода grep как есть 0
когда совпадение найдено. Вы можете сделать это с помощью простого трюка, описанного в этот вопрос. Итак, в конечном итоге ваша команда соли может выглядеть так:
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
Это покажет полный вывод соли, подавит вывод grep и вернет инвертированный код возврата значения grep 1
если обнаружены какие-либо сообщения об ошибках и 0
если не.
Для тех, кто все еще пытается решить эту проблему, вы можете сделать следующее:
salt * state.highstate --retcode-passthrough
или
salt-call * state.highstate --retcode-passthrough