У меня есть интересная проблема с Paramiko.Я использую его для SSHClient в своем коде, где я сначала тестирую соединение, затем подключаюсь (всегда к одному хосту) и, наконец, выполняю задачу.Все это работает очень хорошо, и даже при одновременном запуске, за исключением одного конкретного сценария.Допустим, у меня есть 2 задачи, первая занимает 2 минуты, а вторая - 5 минут.Если я запускаю их одновременно, но только в этом порядке - сначала я запускаю 2-минутное задание, а затем, пока оно выполняется, запускаю 5-минутное;По завершении 2-минутного задания обе задачи завершаются, то есть 5-минутное отключается.Я подозреваю, что проблема связана с ssh.close (), который закрывает оба сеанса, а также их основной транспорт.Я использую потоки и вызываю функцию SSH как отдельные потоки, но это, похоже, не имеет большого значения.
Вот упрощенный код:
connect.py:
import paramiko
HOST = "test.example.com"
USER = "test"
KEY = "/root/.ssh/id_rsa"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
def test_ssh():
try:
ssh.connect(HOST, username=USER, key_filename=KEY)
except Exception as e:
raise ValueError("Connection Error: {}".format(str(e)))
ssh.close()
def run_ssh(cmd, logname):
file = open(logname, 'w')
stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
for line in iter(stdout.readline, ''):
file.write(''.join(line))
file.close()
ssh.close()
app.py:
import threading
from flask import jsonify
from connect import test_ssh, run_ssh
import time
min2 ='/home/test/2min.sh'
log2 = '2minuteoutput.log'
min5 ='/home/test/5min.sh'
log5 = '5minuteoutput.log'
def run(cmd, logname):
try:
test_ssh()
except ValueError as e:
return jsonify({"status": "error", 'message' : str(e)})
else:
somethread = threading.Thread(target=run_ssh, args=(cmd, logname))
somethread.start()
run(min2, log2)
time.sleep(5)
run(min5, log5)
На другом хосте я размещаю2 сценария оболочки, которые я выполняю:
/ home / test / 2min.sh (принадлежит тестовому пользователю и с исполняемым файлом):
#!/bin/bash
echo "Starting 2 minute job at: "`date`
sleep 60
echo "2min job min1" `date`
sleep 60
echo "2min job min2" `date`
echo "Completed 2 minute job at:" `date`
/ home / test / 5min.sh:
#!/bin/bash
echo "Starting 5 minute job at: "`date`
sleep 60
echo " 5 min job: min1" `date`
sleep 60
echo "5min job: min2" `date`
sleep 60
echo "5 min job: min3" `date`
sleep 60
echo "5min job min4" `date`
sleep 60
echo "5min job min5" `date`
echo "Completed 5 minute job at:" `date`
Затем я запускаю его как python app.py и выходные журналы выглядят так:
2minuteoutout.log:
Starting 2 minute job at: Tue Apr 30 20:09:06 UTC 2019
2min job min1 Tue Apr 30 20:10:06 UTC 2019
2min job min2 Tue Apr 30 20:11:06 UTC 2019
Completed 2 minute job at: Tue Apr 30 20:11:06 UTC 2019
5minuteoutput.log:
Starting 5 minute job at: Tue Apr 30 20:09:11 UTC 2019
5 min job: min1 Tue Apr 30 20:10:11 UTC 2019
Обе работы были завершены в 20:11:06 UTC, когда ssh.close () была вызвана из первой работы.
Также вот вывод журнала отладки paramiko:
DEB [20190430-21:20:26.906] thr=1 paramiko.transport: starting thread (client mode): 0xd6ed09b0
DEB [20190430-21:20:26.907] thr=1 paramiko.transport: Local version/idstring: SSH-2.0-paramiko_2.4.2
DEB [20190430-21:20:26.996] thr=1 paramiko.transport: Remote version/idstring: SSH-2.0-OpenSSH_7.4
INF [20190430-21:20:26.997] thr=1 paramiko.transport: Connected (version 2.0, client OpenSSH_7.4)
DEB [20190430-21:20:27.085] thr=1 paramiko.transport: kex algos:['curve25519-sha256', 'curve25519-sha256@libssh.org', 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384', 'ecdh-sha2-nistp521', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512
DEB [20190430-21:20:27.085] thr=1 paramiko.transport: Kex agreed: ecdh-sha2-nistp256
DEB [20190430-21:20:27.085] thr=1 paramiko.transport: HostKey agreed: ssh-ed25519
DEB [20190430-21:20:27.085] thr=1 paramiko.transport: Cipher agreed: aes128-ctr
DEB [20190430-21:20:27.085] thr=1 paramiko.transport: MAC agreed: hmac-sha1
DEB [20190430-21:20:27.086] thr=1 paramiko.transport: Compression agreed: none
DEB [20190430-21:20:27.215] thr=1 paramiko.transport: kex engine KexNistp256 specified hash_algo <built-in function openssl_sha256>
DEB [20190430-21:20:27.216] thr=1 paramiko.transport: Switch to new keys ...
DEB [20190430-21:20:27.216] thr=2 paramiko.transport: Adding ssh-ed25519 host key for test.example.com:
DEB [20190430-21:20:27.217] thr=2 paramiko.transport: Trying discovered key in /root/.ssh/id_rsa
DEB [20190430-21:20:27.299] thr=1 paramiko.transport: userauth is OK
INF [20190430-21:20:27.399] thr=1 paramiko.transport: Authentication (publickey) successful!
DEB [20190430-21:20:27.400] thr=3 paramiko.transport: [chan 0] Max packet in: 32768 bytes
DEB [20190430-21:20:27.484] thr=1 paramiko.transport: Received global request "hostkeys-00@openssh.com"
DEB [20190430-21:20:27.484] thr=1 paramiko.transport: Rejecting "hostkeys-00@openssh.com" global request from server.
DEB [20190430-21:20:27.604] thr=1 paramiko.transport: [chan 0] Max packet out: 32768 bytes
DEB [20190430-21:20:27.604] thr=1 paramiko.transport: Secsh channel 0 opened.
DEB [20190430-21:20:27.683] thr=1 paramiko.transport: [chan 0] Sesch channel 0 request ok
DEB [20190430-21:20:27.767] thr=1 paramiko.transport: [chan 0] Sesch channel 0 request ok
DEB [20190430-21:20:32.491] thr=4 paramiko.transport: starting thread (client mode): 0xd14075c0
DEB [20190430-21:20:32.492] thr=4 paramiko.transport: Local version/idstring: SSH-2.0-paramiko_2.4.2
DEB [20190430-21:20:32.579] thr=4 paramiko.transport: Remote version/idstring: SSH-2.0-OpenSSH_7.4
INF [20190430-21:20:32.579] thr=4 paramiko.transport: Connected (version 2.0, client OpenSSH_7.4)
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: kex algos:['curve25519-sha256', 'curve25519-sha256@libssh.org', 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384', 'ecdh-sha2-nistp521', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: Kex agreed: ecdh-sha2-nistp256
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: HostKey agreed: ssh-ed25519
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: Cipher agreed: aes128-ctr
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: MAC agreed: hmac-sha1
DEB [20190430-21:20:32.667] thr=4 paramiko.transport: Compression agreed: none
DEB [20190430-21:20:32.756] thr=4 paramiko.transport: kex engine KexNistp256 specified hash_algo <built-in function openssl_sha256>
DEB [20190430-21:20:32.757] thr=4 paramiko.transport: Switch to new keys ...
DEB [20190430-21:20:32.758] thr=2 paramiko.transport: Trying discovered key in /root/.ssh/id_rsa
DEB [20190430-21:20:32.841] thr=4 paramiko.transport: userauth is OK
INF [20190430-21:20:32.932] thr=4 paramiko.transport: Authentication (publickey) successful!
DEB [20190430-21:20:32.933] thr=5 paramiko.transport: [chan 0] Max packet in: 32768 bytes
DEB [20190430-21:20:33.016] thr=4 paramiko.transport: Received global request "hostkeys-00@openssh.com"
DEB [20190430-21:20:33.016] thr=4 paramiko.transport: Rejecting "hostkeys-00@openssh.com" global request from server.
DEB [20190430-21:20:33.137] thr=4 paramiko.transport: [chan 0] Max packet out: 32768 bytes
DEB [20190430-21:20:33.138] thr=4 paramiko.transport: Secsh channel 0 opened.
DEB [20190430-21:20:33.224] thr=4 paramiko.transport: [chan 0] Sesch channel 0 request ok
DEB [20190430-21:20:33.310] thr=4 paramiko.transport: [chan 0] Sesch channel 0 request ok
DEB [20190430-21:22:27.780] thr=1 paramiko.transport: [chan 0] EOF received (0)
DEB [20190430-21:22:27.780] thr=1 paramiko.transport: [chan 0] EOF sent (0)
То, что я собрал из журнала - похоже, что paramiko.transport уже использует потоки.Также, если я правильно читаю (?) - открывается 1 канал.Он указан как открытый дважды (для каждого сценария - один раз в 21:20:27 и затем в 21:20:33).Однако оба они называются chan 0, так что может быть один и тот же канал повторно использован?Как только ssh.close () выдается из первого задания, 1 канал закрывается.Этот вид имеет смысл, поскольку он уже имеет активное соединение с тем же сервером, поэтому может использовать его повторно.Я тоже попробовал использовать канал, но получил тот же результат;
Исходя из этого, мне, возможно, потребуется найти способ запуска / принудительного запуска нескольких каналов - это было бы трудно сделать в интерактивном режиме, а с некоторым типом цикла он мог бы открывать неиспользуемые каналы для каждого вызова итребуется логика для отправки следующих вызовов на этот другой канал.
Я хочу убедиться, что приложение, над которым я работаю, полностью способно обрабатывать несколько задач одновременно, поэтому я хотел задать этот вопрос и посмотреть,может ли кто-нибудь, более знакомый с paramiko, дать мне несколько советов - любая помощь очень ценится!