Могу ли я получить код выхода команды, выполненной в подоболочке, через ssh?

Я пытаюсь использовать Paramiko для написания сценария развертывания, и у меня возникают проблемы с кодами выхода из команд, которые я запускаю. Я использую код, аналогичный тому, что использовался в этот ответ, но это немного сложнее. По сути, из наших ящиков для разработчиков мы должны пройти через сервер перехода, а оттуда - на серию производственных машин. Оказавшись там, мы должны переключиться на системного пользователя (sudo su - systemuser), а затем мы можем запускать команды.

Проблема в том, что, насколько я понимаю, у меня есть 3 подоболочки - сеанс ssh, вложенная команда ssh и затем подоболочка su. Я не могу заставить Paramiko вернуть мне код выхода команд во внутренней подоболочке - я предполагаю, что код выхода, который он в конечном итоге вернет, будет кодом команды ssh. Я подозреваю, что эта проблема на самом деле не специфична для Paramiko - поддерживает ли протокол SSH такое использование?

В настоящее время я всегда выполняю:

(my command); echo "Process terminated with exit code $?"

а затем разобрать это на клиенте, но это довольно некрасиво - есть ли способ лучше?


person Colin    schedule 17.03.2011    source источник


Ответы (2)


Я предполагаю, что код выхода, который он в конечном итоге вернет, будет кодом команды ssh. Я подозреваю, что эта проблема на самом деле не специфична для Paramiko - поддерживает ли протокол SSH такое использование?

И да и нет.

Статус выхода возвращается всегда, но он может быть не там, где вы думаете. Как только вы вызываете invoke_shell(), ваш удаленный процесс представляет собой оболочку, возможно, bash. exit_status, который вы получите, будет получен от этой оболочки, не ни одного из запущенных ею процессов. Paramiko (или какая-либо реализация ssh) может когда-либо возвращать статус выхода ваших команд, потому что статусы выхода никогда не видны за пределами этой удаленной оболочки. Вам решать, каким должен быть ваш статус выхода, и выйти из оболочки с помощью exit $EXIT_STATUS (часто достаточно exit $?).

Если вы можете разбить свои команды или обернуть их в сценарий, а затем использовать метод exec_command(), у вас будет прямой доступ к правильному статусу выхода.

В качестве альтернативы вы можете использовать команду оболочки exec в удаленной оболочке, и процесс оболочки будет заменен командой, вызываемой exec, и будет возвращен его статус выхода.

Все три метода устанавливают атрибут channel.exit_status, как и ожидалось.

person JimB    schedule 29.03.2011
comment
Спасибо за ответ - я так и подозревал. Причина, по которой я использую invoke_shell(), заключается в том, что я хочу запускать различные команды на сервере без воссоздания соединения. Мне нужно пройти через окно перехода, поэтому из Paramiko я использую connect() (в окно перехода), invoke_shell() затем выполняю ssh <server>. Оказавшись там, мне нужно переключиться на системного пользователя (sudo su - <user>), тогда я хотел бы иметь возможность выполнять различные команды, не повторяя все вышеперечисленное, но при этом получая коды возврата. Это возможно? - person Colin; 30.03.2011
comment
@Colin - Да, используя методы, которые я показал выше. Вы должны передать коды возврата, которые вы хотите создать резервную копию цепочки, либо exit'ингом оболочки с правильным статусом, либо exec'ингом нужной команды напрямую. - person JimB; 30.03.2011
comment
но это позволяет мне возвращать код выхода только одной команды за сеанс (поскольку exec заменяет текущий процесс). Тогда мне придется повторно подключаться между каждой командой, верно? - person Colin; 30.03.2011
comment
@Colin - да, вы получаете только последний код выхода, возвращенный оболочкой / удаленным процессом. Так работает оболочка и не имеет ничего общего с ssh. Поскольку вы ищете exit_status, я предполагаю, что вы пишете сценарии для этих команд; почему бы не отправить логику на удаленный компьютер в скрипте python / shell, где у вас будет прямой доступ к командам? В противном случае разделите команды и используйте канал ssh как механизм RPC, где вы можете эффективно игнорировать часть оболочки. - person JimB; 30.03.2011
comment
Я запускаю оболочку с -eu, поэтому оболочка срабатывает, как только возникает проблема. Примерно так: echo 'set -eu ; cd wherever ; do something' | ssh host bash или echo "false ; echo haha" | ssh host sudo -u dudekins sh -eu - person Max Murphy; 27.11.2015

У меня проблема, когда на странице руководства для ssh говорится, что он возвращает код выхода процесса, который он запускает, но я не могу заставить его вернуть ненулевой код ошибки. На странице руководства ssh:

 The session terminates when the command or shell on the remote machine
 exits and all X11 and TCP/IP connections have been closed.  The exit sta‐
 tus of the remote program is returned as the exit status of ssh.

Это не похоже на правду.

Но я бы попробовал что-то подобное и посмотрел, что происходит в вашей системе.

% ssh localhost bash -c "exit 3" ; echo $?
0

Когда я запускаю аналогичную команду локально, bash возвращает код выхода.

% bash -c 'exit 3' ; echo $?
3

Однако двойные кавычки будут удалены до того, как ssh покажется командам. Так что давайте попробуем еще цитаты.

% ssh localhost bash -c "'exit 3'" ; echo $?
3

Бинго. «Выход 3» превращался в «выход», за которым следовало игнорируемое слово в командной строке bash. Итак, bash запускал команду «exit».

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

person Chris Quenelle    schedule 17.03.2011
comment
Странно, результат тот же. Я ожидал, что по крайней мере ssh вернет разумный код выхода. Понятия не имею, что там происходит. - person Colin; 18.03.2011
comment
Я просто попробовал это с помощью команды, которая напрямую возвращает код ошибки и работает правильно: ssh localhost "ls blarg"; echo $? правильно возвращает код ошибки. Я думаю, что в вашем примере подоболочка exit возвращает 3 в bash, но bash возвращает 0 (потому что он завершается правильно). - person Colin; 18.03.2011
comment
Я получаю то же самое: ssh localhost bash -c "exit 3" возвращает 0. echo 'exit 3' | ssh localhost bash возвращает 3. Удивительно, но это также возвращает 0: ssh localhost bash -eu -c "exit 3" - person Max Murphy; 27.11.2015