Назад | Перейти на главную страницу

Как сделать так, чтобы модуль выполнения соли возвращал ненулевой код выхода при ошибке

Я пытаюсь использовать 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