Plusieurs commandes au cours d'une session SSH dans une session SSH

10

J'ai une machine locale qui est censée créer une session SSH vers une mastermachine distante , puis une autre session SSH interne de la masterà chacun de certaines télécommandes slaves, puis exécuter 2 commandes, c'est-à-dire supprimer un répertoire spécifique et le recréer.

Notez que la machine locale a SSH sans mot de passe pour le maître et le maître a SSH sans mot de passe pour les esclaves. De plus, tous les noms d'hôtes sont connus sur .ssh/configles machines locales / maîtres et les noms d'hôtes des esclaves sont slaves.txtlocalement et je les lis à partir de là.

Donc, ce que je fais et travaille est le suivant:

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 

Ce cluster est sur Amazon EC2 et j'ai remarqué qu'il y a 6 sessions SSH créées à chaque itération ce qui induit un retard important. Je voudrais combiner ces 3 commandes en 1 pour obtenir moins de connexions SSH. J'ai donc essayé de combiner les 2 premières commandes en

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

Mais cela ne fonctionne pas comme prévu. Il semble exécuter le premier ( rm -rf Input Output Partition) puis quitte la session et continue. Que puis-je faire?

mgus
la source
3
Au lieu d'une telle indirection dans la commande, vous pouvez utiliser une -Joption qui définirait votre hôte de saut.
Hauleth

Réponses:

15

Considérez que &&c'est un opérateur logique. Cela ne signifie pas "exécuter également cette commande", cela signifie "exécuter cette commande si l'autre réussit".

Cela signifie que si la rmcommande échoue (ce qui se produira si l'un des trois répertoires n'existe pas), le mkdirne sera pas exécuté. Cela ne ressemble pas au comportement que vous souhaitez; si les répertoires n'existent pas, c'est probablement bien de les créer.

Utilisation ;

Le point ;- virgule est utilisé pour séparer les commandes. Les commandes sont exécutées séquentiellement, en attendant chacune avant de passer à la suivante, mais leur succès ou leur échec n'a aucun impact les uns sur les autres.

Échapper aux citations intérieures

Les citations à l'intérieur d'autres citations doivent être échappées, sinon vous créez un point final et un point de départ supplémentaires. Votre commande:

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

Devient:

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

Votre commande actuelle, en raison du manque de guillemets échappés, devrait s'exécuter:

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

si cela réussit:

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

Vous remarquerez que la coloration syntaxique montre la commande entière en rouge ici, ce qui signifie que la commande entière est la chaîne transmise à ssh. Vérifiez votre machine locale; vous pouvez avoir les répertoires Input Outputet Partitionoù vous l'exécutiez.

Centimane
la source
Je comprends vos points. Une partie qui m'a dérouté était le point-virgule, car je pensais qu'il exécuterait plus d'une commande en même temps, c'est pourquoi je ne l'ai pas utilisé.
mgus
Le point-virgule n'entraînera pas l'exécution simultanée des commandes, voir ici comme référence pour l'exécution des commandes. Les &commandes s'exécutent en arrière-plan, ce qui signifie qu'elles ne seront pas attendues pour terminer avant de passer à la suivante.
Centimane
10

Vous pouvez toujours définir dans votre Jumpbox Multiplexage dans OpenSSH

Le multiplexage est la possibilité d'envoyer plus d'un signal sur une seule ligne ou connexion. Avec le multiplexage, OpenSSH peut réutiliser une connexion TCP existante pour plusieurs sessions SSH simultanées plutôt que d'en créer une à chaque fois.

Un avantage du multiplexage SSH est que la surcharge de création de nouvelles connexions TCP est éliminée. Le nombre total de connexions qu'une machine peut accepter est une ressource limitée et la limite est plus visible sur certaines machines que sur d'autres et varie considérablement en fonction de la charge et de l'utilisation. Il y a également un retard important lors de l'ouverture d'une nouvelle connexion. Les activités qui ouvrent à plusieurs reprises de nouvelles connexions peuvent être considérablement accélérées grâce au multiplexage.

Pour cela, faites en /etc/ssh/ssh_config:

ControlMaster auto
ControlPath ~/.ssh/controlmasters/ssh_mux_%h_%p_%r
ControlPersist 30m

De cette façon, toutes les connexions consécutives établies au même serveur dans les 30 minutes suivantes seront effectuées en réutilisant la connexion ssh précédente.

Vous pouvez également le définir pour une machine ou un groupe de machines. Tiré du lien fourni.

Host machine1
    HostName machine1.example.org
    ControlPath ~/.ssh/controlmasters/%r@%h:%p
    ControlMaster auto
    ControlPersist 10m
Rui F Ribeiro
la source
C'est intéressant! Existe-t-il un moyen de l'activer et de le désactiver explicitement pour une connexion donnée? Il semble exagéré de changer si radicalement toutes les connexions SSH pour ce cas d'utilisation. Peut-il être utilisé de manière plus précise? Pour commencer à multiplexer uniquement une certaine connexion?
Centimane
@Centimane ouais, a mis à jour la réponse
Rui F Ribeiro
1
Je suggérerais de mettre la prise dans la maison de l'utilisateur plutôt que dans un monde accessible en lecture /tmp/.
heemayl
@heemayl Bon point. Je vais l'éditer sur un ordinateur.
Rui F Ribeiro
@RuiFRibeiro ressemble également, selon man ssh, ControlPath, ControlMasteret ControlPersistsont des options valides pour passer une sshcommande à l' aide -o. Cela pourrait être un cas d'utilisation encore plus précis, configurer le multiplexage dans le premier sshdu script et le recycler pour les autres, mais sinon, évitez la pénalité de performance. Je me demande ce que la référence du multiplexage VS n'est pas pour 3 connexions SSH, étant donné que "Il y a aussi un retard important lors de l'ouverture d'une nouvelle connexion"
Centimane
4

Vous pouvez mettre toutes vos commandes dans un script séparé sur votre serveur "maître".

Script maître

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

Ensuite, dans votre script ssh, appelez-le comme ceci: 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 si tous les fichiers doivent se trouver sur la machine initiale, vous pouvez faire quelque chose comme ceci:

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
jesse_b
la source
1

Il y a quelque temps, j'ai eu l'occasion d'utiliser des sockets de contrôle comme les autres réponses le recommandent (cette réponse est essentiellement une combinaison de l'utilisation de sockets de contrôle comme cette réponse et de scripts comme cette réponse ).

Le cas d'utilisation était un hack: authorized_keysl'utilisateur cible était écrasé périodiquement par une tâche planifiée et je voulais tester rapidement les choses sans passer par la paperasserie nécessaire pour ajouter quelque chose à ce fichier. J'ai donc configuré une boucle while qui a ajouté la clé à ce fichier si nécessaire, exécuté mon test et annulé la boucle. Cependant, il y aurait une petite fenêtre où la tâche planifiée écraserait le fichier et ma boucle serait toujours sleepen cours. Donc, configurer un socket de contrôle au début permettrait à mon script SSH plus tard sans problème:

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

setup-ssh.shest:

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

Et .ssh-config:

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

Et run-test.sh:

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

La séquence se déroule comme suit:

  • Les sources du script principal (illustré en premier) setup-ssh.sh.
  • setup-ssh.shoccupé-boucle les serveurs jusqu'à ce que tous aient une configuration de socket de contrôle. Le hostsfichier répertorie simplement les noms d'hôte du serveur un par ligne.
  • Étant donné que la configuration spécifiant le socket de contrôle est uniquement présente ${CONFIG_DIR}/scripts/.ssh-config, à moins que je ne spécifie ce fichier à l'aide -F, les connexions SSH ne l'utiliseront pas. Cela me permet donc d'utiliser la prise de contrôle uniquement là où j'en ai besoin en utilisant l' Foption.
  • Le script de configuration copie également le script d'exécution du test sur les serveurs. Le script d'exécution lui-même contient un tas de commandes, et parce que j'ai copié le script d'exécution, je n'ai pas à me soucier d'une couche supplémentaire de devis pour SSH (et de la surcharge cognitive supplémentaire pour déterminer ce qui sera développé quand).
  • Ensuite, le script principal utilise xargspour répartir la charge de travail sur les serveurs, en démarrant de nouveaux travaux dès la fin de ceux-ci.
muru
la source