Múltiplos comandos durante um SSH dentro de uma sessão SSH

8

Eu tenho uma máquina local que deve fazer uma sessão SSH para uma máquina master remota e depois outra sessão SSH interna do master para cada um dos slaves remotos, e então executar 2 comandos ie excluir um diretório específico e recriá-lo.

Note que a máquina local tem SSH sem senha para o mestre e o mestre tem SSH sem senha para os escravos. Além disso, todos os nomes de host são conhecidos em .ssh/config das máquinas locais / principais, e os nomes dos hosts dos escravos estão em slaves.txt localmente e eu os leio de lá.

Então, o que eu faço e trabalho é isso:

username="ubuntu"
masterHostname="myMaster"
while read line
do

    #Remove previous folders and create new ones.
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition""
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "mkdir -p EC2_WORKSPACE/$project Input Output Partition""


    #Update changed files...
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""

done < slaves.txt 

Este cluster está no Amazon EC2 e notei que há 6 sessões SSH criadas em cada iteração, o que induz um atraso significativo. Eu gostaria de combinar esses 3 comandos em 1 para obter menos conexões SSH. Então eu tentei combinar os dois primeiros comandos em

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

Mas não funciona como esperado. Parece executar o primeiro ( rm -rf Input Output Partition ) e depois sai da sessão e continua. O que posso fazer?

    
por mgus 26.07.2017 / 19:29

4 respostas

14

Considere que && é um operador lógico. Não não significa "também executar este comando" significa "executar este comando se o outro for bem-sucedido".

Isso significa que, se o comando rm falhar (o que acontecerá se algum dos três diretórios não existir), o mkdir não será executado. Isso não soa como o comportamento que você quer; Se os diretórios não existirem, provavelmente é bom criá-los.

Use ;

O ponto e vírgula ; é usado para separar comandos. Os comandos são executados sequencialmente, esperando por cada um antes de continuar para o próximo, mas seu sucesso ou falha não tem impacto um no outro.

Escape de citações internas

As citações dentro de outras citações devem ter escape, caso contrário você estará criando um ponto final e um ponto inicial extra. Seu comando:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

Torna-se:

ssh -n $username@$masterHostname "ssh -t -t $username@$line \"rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input OutputPartition\""

Seu comando atual, devido à falta de citações com escape, deve estar em execução:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition

se isso for bem sucedido:

mkdir -p EC2_WORKSPACE/$project Input Output Partition"" # runs on your local machine

Você notará que o realce da sintaxe mostra o comando inteiro como vermelho aqui, o que significa que o comando inteiro é a cadeia que está sendo passada para o ssh. Verifique sua máquina local; você pode ter os diretórios Input Output e Partition onde você estava executando isso.

    
por 26.07.2017 / 19:51
8

Você sempre pode definir em seu Jumpbox Multiplexing no OpenSSH

Multiplexing is the ability to send more than one signal over a single line or connection. With multiplexing, OpenSSH can re-use an existing TCP connection for multiple concurrent SSH sessions rather than creating a new one each time.

An advantage with SSH multiplexing is that the overhead of creating new TCP connections is eliminated. The overall number of connections that a machine may accept is a finite resource and the limit is more noticeable on some machines than on others, and varies greatly depending on both load and usage. There is also significant delay when opening a new connection. Activities that repeatedly open new connections can be significantly sped up using multiplexing.

Para isso, use /etc/ssh/ssh_config :

ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r
ControlPersist 30m

Desta forma, quaisquer conexões consecutivas feitas no mesmo servidor nos 30 minutos seguintes serão feitas reutilizando a conexão ssh anterior.

Você também pode defini-lo para uma máquina ou grupo de máquinas. Extraído do link fornecido.

Host machine1
    HostName machine1.example.org
    ControlPath ~/.ssh/controlmasters/%r@%h:%p
    ControlMaster auto
    ControlPersist 10m
    
por 26.07.2017 / 20:02
3

Você pode colocar todos os seus comandos em um script separado em seu servidor "mestre".

Script mestre

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"

Em seguida, no seu script ssh, chame assim: Script SSH

username="ubuntu"
masterHostname="myMaster"
while read line
do
ssh -n $username@$masterHostname "ssh -t -t $username@$line < /path/to/masterscript.sh"
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""
done < slaves.txt 

OU se todos os arquivos devem estar na máquina inicial, você poderia fazer algo assim:

script1

script2="/path/to/script2"
username="ubuntu"
while read line; do
cat $script2 | ssh -t -t $username@line
done < slaves.txt

script2

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"
rsync --delete -avzh "/EC2_NFS/$project/* EC2_WORKSPACE/$project"

script ssh

script1="/path/to/script1"
username="ubuntu"
masterHostname="myMaster"
cat $script1 | ssh -n $username@$masterHostname
    
por 26.07.2017 / 19:34
1

Algum tempo atrás, eu tive a oportunidade de usar soquetes de controle como as outras respostas recomendam (esta resposta é essencialmente uma combinação de usar soquetes de controle como esta resposta e scripts como esta resposta ).

O caso de uso foi um hack: O authorized_keys do usuário de destino foi sobrescrito periodicamente por uma tarefa agendada e eu queria testar rapidamente as coisas sem passar pela burocracia necessária para adicionar algo a esse arquivo. Então eu configurei um loop while que adicionou a chave a esse arquivo conforme necessário, executei meu teste e cancelei o loop. No entanto, haveria uma pequena janela onde a tarefa agendada sobrescreveria o arquivo e meu loop ainda seria sleep ing. Então, configurar um soquete de controle no início deixaria meu script SSH mais tarde sem problemas:

#! /bin/bash -xe
. "${CONFIG_DIR}/scripts/setup-ssh.sh"

# Build and test
export TEST_LABEL="${_started_by}-${BUILD_TAG%-BUILD*}"
#...
xargs --arg-file test-list \
    --no-run-if-empty \
    --process-slot-var=NUM \
    --max-procs=${#SERVERS[@]} \
    --max-args="${BATCH_SIZE:-20}" \
    "${CONFIG_DIR}/scripts/run-test.sh"

Onde setup-ssh.sh é:

export SSH_CONFIG="${CONFIG_DIR}/scripts/.ssh-config"
mapfile -t SERVERS < "${CONFIG_DIR}/scripts/hosts"

for SERVER in "${SERVERS[@]}"
do
    while ! ssh -F "${SSH_CONFIG}" "${SERVER}" -fnN; do sleep 1; done
    scp -F "${SSH_CONFIG}" "${CONFIG_DIR}/scripts/ssh-script.sh" "${SERVER}":"${TEST_LABEL}.sh"
done

e .ssh-config :

Host test-*
  User test
  StrictHostKeyChecking no
  ControlMaster auto
  ControlPath /tmp/ssh-%h-%p-%r

e run-test.sh :

mapfile -t TEST_SERVERS < "${CONFIG_DIR}/scripts/hosts"
ssh -F "${SSH_CONFIG}" "${TEST_SERVERS[$NUM]}" "./${TEST_LABEL}.sh"

A sequência é assim:

  • O script principal (mostrado primeiro) origina setup-ssh.sh .
  • setup-ssh.sh busy-loops os servidores até que todos eles tenham uma configuração de soquete de controle. O arquivo hosts simplesmente lista os nomes de host do servidor, um por linha.
  • Como a configuração que especifica o soquete de controle é somente em ${CONFIG_DIR}/scripts/.ssh-config , a menos que eu especifique esse arquivo usando -F , as conexões SSH não o usarão. Então, isso me permite usar o soquete de controle somente onde eu precisar deles usando a opção F .
  • O script de configuração também copia o script de execução de teste para os servidores. O próprio script de execução contém vários comandos e, como copiei o script de execução, não preciso me preocupar com uma camada adicional de cotação para SSH (e a sobrecarga cognitiva adicional para descobrir o que é expandido quando).
  • Em seguida, o script principal usa xargs para distribuir a carga de trabalho pelos servidores, iniciando novas tarefas assim que a execução é finalizada.
por 27.07.2017 / 06:26