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

Удаленное синхронно-асинхронное выполнение с помощью SSH

TL; DR

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

подробности

У меня есть сценарий на удаленном сервере, который медленно загружает файл размером в несколько гигабайт. Я хотел бы запустить этот сценарий через SSH с локального сервера с помощью ssh remote-server 'nohup / path / to / script arguments', но уничтожить SSH-соединение, когда я знаю, что сценарий успешно начал загрузку. После запуска SSH-соединение перестает служить какой-либо полезной цели, систематически дает сбой где-то во время загрузки и блокирует выполнение на локальном сервере.

Я не могу просто сделать ssh -f или ssh & потому что мне нужна команда для сбоя на локальном сервере, если удаленный сценарий не запускается, дает сбой при первых командах перед загрузкой или если удаленный сервер недоступен.

Я пробовал разные nohup и screen ухищрения. Самое близкое, что я получил, было следующее:

Но как-то screen все еще убивают ...

Образец кода воспроизведения

Посмотрите на подсистемы 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. Также есть дополнительное преимущество: экран можно снова подключить позже.