Я хочу удаленно выполнить сценарий, который начинается синхронно (так, чтобы локальная команда ssh не выполнялась, если предварительные команды терпят неудачу), а затем переходит в асинхронный режим, таким образом завершая локальную команду ssh.
У меня есть сценарий на удаленном сервере, который медленно загружает файл размером в несколько гигабайт. Я хотел бы запустить этот сценарий через SSH с локального сервера с помощью ssh remote-server 'nohup / path / to / script arguments', но уничтожить SSH-соединение, когда я знаю, что сценарий успешно начал загрузку. После запуска SSH-соединение перестает служить какой-либо полезной цели, систематически дает сбой где-то во время загрузки и блокирует выполнение на локальном сервере.
Я не могу просто сделать ssh -f
или ssh &
потому что мне нужна команда для сбоя на локальном сервере, если удаленный сценарий не запускается, дает сбой при первых командах перед загрузкой или если удаленный сервер недоступен.
Я пробовал разные nohup
и screen
ухищрения. Самое близкое, что я получил, было следующее:
Запускается локальным сервером:
ssh -t me@remote-server 'screen -S long-download /path/to/download.sh'
или
ssh -t me@remote-server 'nohup screen -S long-download /path/to/download.sh'
В download.sh
запущен на удаленном сервере:
preliminary-instructions
# if anything fails so far then the local server's ssh command should fail synchronously
download-command &
some-more-checking
screen -d long-download # we can now safely end the ssh session
Но как-то screen
все еще убивают ...
На удаленном сервере в /path/to/test.sh
:
#!/bin/bash
# uncomment this line to validate synchronous failure
sleep 10 && echo foo >/tmp/bar &
screen -d long-download
Локально:
ssh -t me@remote-server 'nohup screen -S long-download /path/to/test.sh'
Посмотрите на подсистемы ssh. Я делаю нечто подобное, но не со сценарием (т.е. я использую программы, скомпилированные с помощью a.out / elf). Но я только что протестировал с помощью сценария bash, и он работает.
На странице руководства ssh:
-s May be used to request invocation of a subsystem on the remote
system. Subsystems are a feature of the SSH2 protocol which
facilitate the use of SSH as a secure transport for other appli-
cations (eg. sftp(1)). The subsystem is specified as the remote
command.
Используйте -s (нижний регистр) на клиенте, чтобы указать подсистему
Добавьте еще одну запись подсистемы в sshd_config на сервере, которая указывает на ваш скрипт.
# override default of no subsystems
Subsystem logger /usr/local/libexec/my-logger.sh
Subsystem sftp /usr/libexec/sftp-server
Ваш скрипт должен быть запущен так же, как и любой другой файл с разрешениями на выполнение. Мой пример:
#! /usr/local/bin/bash
logger "testing 1.2.3"
echo "return text from my-logger"
exec 0>&- # close stdin
exec 0<&-
exec 1>&- # close stdout
exec 1<&-
exec 2>&- # close stderr
exec 2<&-
logger "subsystem: nohup new script"
nohup /path/to/another/script/logger2.sh &
logger "subsystem: the subsystem started script is now done"
exit 0
Вы должны иметь возможность возвращать полезный текст ошибки в случае успеха или неудачи. Соединение ssh (и, следовательно, stdin, stdout и stderr) работает, пока подсистема не завершит его. Подсистема может продолжать работать или нет.
Пусть ваш другой скрипт (logger2.sh выше) спит в течение 5-10 минут, чтобы вы могли использовать netstat, чтобы увидеть, что соединение ssh пропало, клиент ssh вернулся в оболочку и, например, ps ax показывает, что скрипт все еще работает в фоновом режиме. Этому сценарию также может потребоваться закрыть fd и т. Д. Это просто быстрый пример. Удачи.
Альтернативное решение на ответ Бостонского водителя: screen -d -m
.
В async-launcher.sh
:
#!/bin/bash
echo connected &&
# preliminary-command &&
screen -S index-fetch -d -m $(cd ${0%/*} && pwd -P)/long-download.sh
sleep 5 # ensure long-download.sh didn't immediately fail
if ((`screen -ls | grep index-fetch | wc -l`)); then
echo ok
else
echo ko
exit 1
fi
И long-download.sh
может содержать все асинхронные команды.
Запуск с простым ssh me@remote-server /path/to/async-launcher.sh
. Также есть дополнительное преимущество: экран можно снова подключить позже.