Execução síncrona-assíncrona remota com SSH

3

TL; DR

Eu quero executar remotamente um script que comece de forma síncrona (para que o comando ssh local falhe se os comandos preparatórios falharem) e, em seguida, assíncrono, finalizando assim o comando ssh local.

Detalhes

Eu tenho um script em um servidor remoto que baixa lentamente um arquivo de vários gigabytes. Eu gostaria de lançar este script via SSH a partir do servidor local com o servidor remoto ssh 'nohup / path / to / script argumentos', mas mata a conexão SSH quando eu sei que o script foi iniciado com sucesso o download. Uma vez iniciada, a conexão SSH não serve a nenhum propósito útil, falha sistematicamente em algum lugar durante os downloads e bloqueia a execução no servidor local.

Não posso fazer apenas ssh -f ou ssh & porque preciso do comando para falhar no servidor do servidor local se o script remoto não iniciar, falhar nos primeiros comandos antes do download ou se o controle remoto servidor não está acessível.

Eu tentei vários truques nohup e screen . O mais perto que cheguei foi o seguinte:

  • Lançado pelo servidor local:

    ssh -t me@remote-server 'screen -S long-download /path/to/download.sh'
    

    ou

    ssh -t me@remote-server 'nohup screen -S long-download /path/to/download.sh'
    
  • Em download.sh lançado no servidor remoto:

    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
    

Mas, de alguma forma, screen ainda é morto ...

Exemplo de código de reprodução

  • Em um servidor remoto, em /path/to/test.sh :

    #!/bin/bash
    # uncomment this line to validate synchronous failure
    sleep 10 && echo foo >/tmp/bar &
    screen -d long-download
    
  • Localmente:

    ssh -t me@remote-server 'nohup screen -S long-download /path/to/test.sh'
    
por instanceof me 19.07.2013 / 14:48

2 respostas

2

Veja os subsistemas ssh. Eu faço algo semelhante, mas não com um script (ou seja, eu uso programas compilados a.out / elf.) Mas eu apenas testei com um script bash e funciona.

Da página de manual do 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.

Use -s (minúsculas) no cliente para especificar o subsistema

Adicione outra entrada do subsistema ao sshd_config no servidor que aponta para o seu script.

    # override default of no subsystems
Subsystem       logger  /usr/local/libexec/my-logger.sh
Subsystem       sftp    /usr/libexec/sftp-server

Seu script deve ser iniciado como qualquer outro arquivo com permissões de execução. Meu exemplo:

#! /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  

Você deve poder retornar um texto de erro útil para sucesso ou falha. A conexão ssh (e, portanto, stdin, stdout e stderr) é até o subsistema terminar. O subsistema pode continuar sendo executado ou não.

Faça com que seu outro script (logger2.sh acima) durma por 5-10 minutos para que você possa usar o netstat para ver a conexão ssh desaparecer, o cliente ssh voltar para o shell e, por exemplo, ps ax mostra que o script ainda está sendo executado em segundo plano. Este script também pode precisar fechar o fd etc. É apenas um exemplo rápido. Boa sorte.

    
por 19.07.2013 / 21:28
1

Solução alternativa para a resposta do BostonDriver: screen -d -m .

Em 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

E long-download.sh pode conter todos os comandos assíncronos.

Inicie com um simples ssh me@remote-server /path/to/async-launcher.sh . Também tem um benefício adicional: a tela pode ser reconectada posteriormente.

    
por 24.07.2013 / 17:48