Обработка исключений в скриптах bash

#bash #jenkins #jboss #wildfly

#bash #дженкинс #jboss #wildfly

Вопрос:

У меня есть скрипт bash (выполняемый Дженкинсом), который вызывает в один момент

 local STATUS=$($SERVER_DIR/bin/jboss-cli.sh --controller=$WILDFLY_CONTROLLER --connect --user=$ADMIN_USER --password=$ADMIN_PW command=:shutdown --timeout=$JBOSSTIMEOUT);
  

Единственная цель этого фрагмента — завершить запущенный процесс wildfly. Если сам вызов будет успешным, но по какой-либо причине wildfly не был завершен, я также добавил другую проверку, которая выполняется несколькими секундами позже

 SERVER_PID=`ps aux | grep $SERVER_DIR | grep 'wildfly.xml' | grep -v grep | tr -s ' ' | cut -d ' ' -f 2`;
if [[ ! -z $SERVER_PID ]] ; then
        kill -9 $SERVER_PID;
    fi
  

Однако время от времени — я не смог выяснить, при каких обстоятельствах — фрагмент ведет себя не так, как ожидалось.

Тип проблемы 1)

Вызов jboss-cli.sh приводит к исключению

 > 2019-02-27_22-05-17 [INFO] Trying to stop wildfly service with jboss-cli.sh
/opt/wildfly/bin/jboss-cli.sh --controller=10.0.1.1:9990 --connect --user=XXXX --password=XXXX command=:shutdown --timeout=120
org.jboss.as.cli.CliInitializationException: Failed to connect to the controller
    at org.jboss.as.cli.impl.CliLauncher.initCommandContext(CliLauncher.java:278)
    at org.jboss.as.cli.impl.CliLauncher.main(CliLauncher.java:241)
    at org.jboss.as.cli.CommandLineMain.main(CommandLineMain.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.modules.Module.run(Module.java:312)
    at org.jboss.modules.Main.main(Main.java:460)
Caused by: org.jboss.as.cli.CommandLineException: The controller is not available at 10.0.1.27:9990
    at org.jboss.as.cli.impl.CommandContextImpl.tryConnection(CommandContextImpl.java:1028)
    at org.jboss.as.cli.impl.CommandContextImpl.connectController(CommandContextImpl.java:840)
    at org.jboss.as.cli.impl.CommandContextImpl.connectController(CommandContextImpl.java:819)
    at org.jboss.as.cli.impl.CliLauncher.initCommandContext(CliLauncher.java:276)
    ... 8 more
Caused by: java.io.IOException: java.net.ConnectException: JBAS012144: Could not connect to http-remoting://10.0.1.1:9990. The connection timed out
    at org.jboss.as.controller.client.impl.AbstractModelControllerClient.executeForResult(AbstractModelControllerClient.java:129)
    at org.jboss.as.controller.client.impl.AbstractModelControllerClient.execute(AbstractModelControllerClient.java:71)
    at org.jboss.as.cli.impl.CommandContextImpl.tryConnection(CommandContextImpl.java:1005)
    ... 11 more
Caused by: java.net.ConnectException: JBAS012144: Could not connect to http-remoting://10.0.1.1:9990. The connection timed out
    at org.jboss.as.protocol.ProtocolConnectionUtils.connectSync(ProtocolConnectionUtils.java:119)
    at org.jboss.as.protocol.ProtocolConnectionManager$EstablishingConnection.connect(ProtocolConnectionManager.java:256)
    at org.jboss.as.protocol.ProtocolConnectionManager.connect(ProtocolConnectionManager.java:70)
    at org.jboss.as.protocol.mgmt.FutureManagementChannel$Establishing.getChannel(FutureManagementChannel.java:204)
    at org.jboss.as.cli.impl.CLIModelControllerClient.getOrCreateChannel(CLIModelControllerClient.java:169)
    at org.jboss.as.cli.impl.CLIModelControllerClient$2.getChannel(CLIModelControllerClient.java:129)
    at org.jboss.as.protocol.mgmt.ManagementChannelHandler.executeRequest(ManagementChannelHandler.java:117)
    at org.jboss.as.protocol.mgmt.ManagementChannelHandler.executeRequest(ManagementChannelHandler.java:92)
    at org.jboss.as.controller.client.impl.AbstractModelControllerClient.executeRequest(AbstractModelControllerClient.java:236)
    at org.jboss.as.controller.client.impl.AbstractModelControllerClient.execute(AbstractModelControllerClient.java:141)
    at org.jboss.as.controller.client.impl.AbstractModelControllerClient.executeForResult(AbstractModelControllerClient.java:127)
    ... 13 more
packet_write_wait: Connection to XXX.XXX.XXX.XXX port 22: Broken pipe
Build step 'Execute shell' marked build as failure
  

что, в свою очередь, прерывает сценарий bash и, следовательно, задание Дженкинса.
Итак, вопрос 1: как я могу перехватывать исключения и убедиться, что скрипт bash обработан, а wildfly завершен с помощью kill-switch.

Тип проблемы 2)

иногда вызов зависает, и консоль показывает мне только

2019-02-27_22-05-17 [ИНФОРМАЦИЯ] Попытка остановить службу wildfly с jboss-cli.sh /opt/wildfly/bin/jboss-cli.sh —контроллер =10.0.1.1:9990 —подключение —пользователь=XXXX —пароль =XXXX команда =: завершение работы —тайм-аут= 120

Похоже, что свойство timeout в jboss не работает должным образом. Итак, вопрос 2: как я могу убедиться, что вызов завершен и не выполняется / не ожидает бесконечно?

Спасибо тебе, Ричард

Комментарии:

1. В bash нет такого понятия, как исключения. Скорее всего, вы получаете код состояния != 0, и ваш скрипт где-то проверяет это значение. Опубликуйте код своего скрипта, если хотите получить более подробный ответ.

2. Также, пожалуйста, публикуйте каждую проблему как отдельный вопрос в stackoverflow.

Ответ №1:

Хотя это и не совсем одно и то же, поведение в стиле исключения может быть в определенной степени эмулировано в bash с помощью trap .

Прежде чем вы попробуете это, лучше всего по-настоящему разобраться в них, поэтому я настоятельно рекомендую вам ознакомиться с руководством по Bash, особенно с концепцией кодов выхода, проверенных условными обозначениями.

Обычно я использую что-то вроде этого:

 trap 'echo >amp;2 "ERROR in $BASH_SOURCE at line $LINENO, Aborting"; exit $LINENO;' ERR
  

ERR (обычно не чувствительный к регистру) — это специальный триггер в bash, который вызывает любой установленный на нем код-ловушку всякий раз, когда из выполненной команды возвращается неперехваченная ошибка. Например:

 $: trap 'echo OW' err
$: false
OW
  

false всегда возвращает код выхода, равный 1, поэтому он запускает ловушку, если не перехвачен, например:

 $: trap 'echo OW' err
$: false || echo nope
nope
  

|| упоминается вместе с amp;amp; внизу ссылки на условные обозначения, но в основном,
amp;amp; вычисляет это правостороннее выражение, если левостороннее выражение возвращает статус выхода true — a 0 . || вычисляет это правостороннее выражение, если левостороннее выражение возвращает false ненулевой статус завершения. Любой из этих методов улавливает (потребляет) ошибку, предотвращая ее запуск, как и большинство других условных тестов состояния выхода.

Итак, предположим, что есть файл xmp с содержимым «Hello» и вышеупомянутая ловушка на месте.

 $: echo Hello>xmp                                  # create simple file
$: grep foo xmp                                    # uncaught fail will trigger trap
OW
$: grep Hello xmp                                  # success doesn't trigger trap
Hello
$: if grep foo xmp; then echo ok; else echo no; fi # caught exception doesn't trigger trap
no
$: grep Hello xmp amp;amp; echo ok || echo no            # success, no trigger
Hello
ok
$: grep foo xmp amp;amp; echo ok || echo no              # caught, no trigger
no
$: grep foo xmp || false                           # LHS caught, RHS triggers trap
OW
$: grep Hello xmp || false                         # LHS doesn't trigger RHS, no error, no trigger
Hello
$: grep foo xmp ||:                                # explicit ignore, : is an alias for true
# WATCH OUT FOR THIS ONE -
$: grep foo xmp amp;amp; echo ok                         # CHECKED, so *caught*
# note no trigger on the last one, because it was tested, even if not explicitly handled...
  

Они могут вам сильно помочь, а могут и не помочь, но всегда приятно иметь возможность поддерживать постоянное поведение для любой неперехваченной ошибки, а затем явно обрабатывать все, что, как вы знаете, может привести к сбою, но что вы можете исправить, или это действительно не имеет значения.

Просто убедитесь, что вы понимаете, что он делает и как это работает, чтобы это вас не удивило. Всегда проверяйте, что он выполняет то, что вы ожидаете.