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

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

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

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

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

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

2 ответа

Решение

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

И да и нет.

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

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

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

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

У меня возникла проблема, когда на странице man для '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 выполнял команду "выход".

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

Другие вопросы по тегам