зависание ssh-процессов, запущенных из скрипта

зависание ssh-процессов, запущенных из скрипта

Я создаю несколько виртуальных машин с помощью скрипта. В ходе этого я меняю имена виртуальных машин с помощью SSH. По какой-то причине, когда я запускаю следующую команду для трех виртуальных машин, она работает, а для магического числа при создании семи виртуальных машин SSH зависает. Может кто-нибудь объяснить это поведение?

часть скрипта. Этот скрипт выполняется одновременно для указанных X виртуальных машин.

...
ssh-keygen -f ~/.ssh/known_hosts -R $IP
ssh-keyscan $IP >> ~/.ssh/known_hosts
SSH="ssh -i $SSH_KEY -o PasswordAuthentication=no"

echo "hostname $hostname && 
    echo HOSTNAME=$hostname >> /etc/sysconfig/network && 
    echo 127.0.0.1 $hostname >> /etc/hosts " | ssh -i $SSH_KEY -o PasswordAuthentication=no root@IP
...

незавершающиеся процессы ssh

rag       2867  2808  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm4
rag       2869  2812  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm7
rag       2872  2818  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm1
rag       2875  2811  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm6
rag       2879  2814  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm5
rag       2881  2813  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm3
rag       2884  2807  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm2

я получил след на одном из запущенных процессов.

...
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
rt_sigreturn(0x16)                      = -1 EINTR (Interrupted system call)
rt_sigaction(SIGALRM, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTSTP, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTTOU, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
close(4)                                = 0
kill(2867, SIGTTOU)                     = 0
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
open("/dev/tty", O_RDWR)                = 4
rt_sigaction(SIGALRM, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGHUP, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGINT, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGPIPE, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGQUIT, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTERM, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTSTP, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTTIN, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTTOU, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon echo ...}) = ? ERESTARTSYS (To be restarted)
...

решение1

Это похоже на состояние гонки, и, глядя на ваш сценарий, я, кажется, понимаю, в чем дело.

Насколько я понимаю, у вас есть скрипт, содержащий следующие 2 строки (среди прочих):

ssh-keygen -f ~/.ssh/known_hosts -R $IP
ssh-keyscan $IP >> ~/.ssh/known_hosts

И затем вы запускаете этот скрипт несколько раз.

Эта последовательность событий может объяснить вашу проблему:

  1. Один из скриптов открывается ~/.ssh/known_hostsдля выполнения ssh-keygen -Rкоманды. В этот момент ssh-keygenкоманда считывает весь файл в память, чтобы удалить целевую строку.
  2. Другой скрипт только что завершил выполнение ssh-keyscanи записал строку в файл.
  3. Первый процесс скрипта ssh-keygen(тот, что из шага № 1) начинает записывать файл, но поскольку он прочитал файл до завершения шага № 2, файл, который он записывает, не содержит строку, добавленную шагом № 2. Поэтому строка из шага № 2 стирается.
  4. Второй скрипт переходит к выполнению ssh, только ключ хоста отсутствует known_hostsиз-за проблемы, упомянутой в шаге № 3. Поэтому ssh зависает, требуя от пользователя подтверждения ключа.

Подробнее:
фоновые программы не могут читать с терминала, попытка сделать это приводит к тому, что эта программа получает SIGTTIN. Однако в вашем strace показано, что программа получает SIGTTOU. Обычно фоновые программы могут писать на терминал без проблем, однако OpenSSH явно включает параметр терминала, который называется , tostopчто приводит к такому поведению. Идя еще дальше, OpenSSH имеет обработчик сигналов для SIGTTOU (среди прочих), что приводит к тому, что код OpenSSH переходит в бесконечный цикл, пока вы не переведете процесс на передний план (в этот момент он может отобразить приглашение и прекратить получать сигнал).

Другой вопрос, как вы собираетесь решать эту проблему.

  • Одним из решений было бы добавить блокировку (есть flockутилита, которую вы можете использовать) и заблокировать known_hostsфайл перед этими двумя строками, а затем разблокировать его после их завершения.
  • Другим решением было бы добавить опцию ssh StrictHostKeyChecking=no. Вы уже сводите на нет смысл файла known_hostsэтими двумя строками скрипта, так что вы могли бы просто отключить его вообще.

Связанный контент