Уведомления

Группа в Telegram: присоединиться | Jabber-конференция сообщества: pythonua@conference.jabber.ru

#1 Май 10, 2007 13:29:43

jan2ary
От:
Зарегистрирован: 2006-11-21
Сообщения: 49
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

Задача: требуется обойти несколько хостов с запуском определенной команды. В двух словах: собрать статистику типа df -h.
Решил использовать paramiko с авторизацией по ключу, а хосты обходить в отдельных потоках.

Вкратце: здесь config содержит настройки хостов и список интересующих точек монтирования. Результат пиклится в дамп.
Проблема в том, что если monitored_hosts содержит больше одного хоста, то скрипт создает только один дамп, для второго выдается ошибка SSHException: Negotiation failed. При чем если поставить паузу в 1 сек в цикле после dg.start(), то все проходит нормально. А если паузу поставить в 0.5, то второй файл получается обрезанным.

Есть у кого-либо подобный опыт, поделитесь решением?
python 2.4.3, paramiko 1.7

import paramiko, os, re, pickle
from ConfigParser import ConfigParser
import threading
import sys
sys.path.append('.')
import config
monitored_hosts = [config.host1, config.host2, ]
class DataGatherer(threading.Thread):
    def __init__(self, entry):
        super(DataGatherer, self).__init__()
        self.cli = paramiko.SSHClient()
        self.cli.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
        self.e = entry
    def run(self):
        try:
            try:
                self.cli.connect(self.e.host, self.e.port, self.e.username)
                stdin, stdout, stderr = self.cli.exec_command( self.e.df_command )
                lst = list()
                for line in stdout:
                    items = re.match(df_format, line.strip())
                    data = dict()
                    for col in cols:
                        data[col] = items.group(col)
                    if data['mountpoint'] in self.e.mountpoints:
                        lst.append(data)
                f = open('tmp/%s.df.dmp' % self.e.host, 'wb')
                pickle.dump( lst , f)
                f.close()
            except Exception, info:
                print "Exception occured: %s" % info
        finally:
            if self.cli:
                self.cli.close()
cols = ['filesystem', 'size', 'used', 'avail', 'capacity', 'mountpoint']
df_format = r'(?P<filesystem>\S+)\s+(?P<size>\S+)\s+(?P<used>\S+)\s+(?P<avail>\S+)\s+(?P<capacity>\S+)\s+(?P<mountpoint>\S+)'
if __name__ == '__main__':
    import time
    for entry in monitored_hosts:
        dg = DataGatherer(entry)
        dg.start()

Спасибо.



Офлайн

#2 Май 10, 2007 17:06:35

slivlen
От:
Зарегистрирован: 2006-07-06
Сообщения: 764
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

Ошибка не особо информативная :) Что он пишет в логах?



Офлайн

#3 Май 10, 2007 17:33:45

jan2ary
От:
Зарегистрирован: 2006-11-21
Сообщения: 49
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

Сейчас 5 хостов в цикле, потоки именую названиями хостов. C паузой 1.5 сек. все работает. Без паузы вот такой букет:

Exception in thread host2:
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 259, in connect
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 399, in start_client
SSHException: Negotiation failed.

Exception in thread host1:
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 279, in connect
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 390, in _auth
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 1176, in auth_publickey
File "build/bdist.linux-x86_64/egg/paramiko/auth_handler.py", line 163, in wait_for_response
EOFError

Exception in thread host3:
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 259, in connect
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 399, in start_client
SSHException: Negotiation failed.

Exception in thread host4:
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 259, in connect
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 398, in start_client
EOFError

Exception in thread host5:
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 259, in connect
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 398, in start_client
EOFError
ОС: домашняя - opensuse, удаленные - HP-UX, Solaris
К тому же иногда характер ошибок меняется, может быть вариант с
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 259, in connect
File "build/bdist.linux-x86_64/egg/paramiko/transport.py", line 398, in start_client
SSHException: Error reading SSH protocol banner(9, 'Bad file descriptor')
и
Traceback (most recent call last):
File "/usr/lib64/python2.4/threading.py", line 442, in __bootstrap
self.run()
File "bin/gatherer.py", line 22, in run
self.cli.connect(self.e.host, self.e.port, self.e.username)
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 279, in connect
File "build/bdist.linux-x86_64/egg/paramiko/client.py", line 406, in _auth
AuthenticationException: Authentication failed.



Отредактировано (Май 10, 2007 17:39:01)

Офлайн

#4 Май 10, 2007 17:46:32

slivlen
От:
Зарегистрирован: 2006-07-06
Сообщения: 764
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

Не этот лог(хотя это тоже полезно посмотреть). Включи перенаправление логов в файл. Может это что-то прояснит.

paramiko.util.log_to_file('/tmp/param.log')



Офлайн

#5 Май 10, 2007 18:42:18

ods
От:
Зарегистрирован: 2007-03-03
Сообщения: 47
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

Есть подозрение, что paramiko (или модуль, который он использует для SSH) далеко не thread-safe. Обычно такие вещи указываются в документации. Пока что все ошибки возникают в методе connect - можно попробовать устанавливать lock перед его вызовом и снимать после. Есть небольшой шанс, что поможет. Но это неправильный подход: часто бывает, что код вполне работает, пока не наскочишь на неприятное место, и будешь потом долго биться с отладкой. Правиль перед использованием любого модуля в многопоточном приложении узнать точно (прочитав документацию), какие части его бузопасны для использования в разных потоках.
Ну и, конечно же, fork спасёт в любом случае :)



Офлайн

#6 Май 10, 2007 19:30:56

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

threading vs. paramiko

Напишите в официальный список рассылки paramiko.
Если проблемы с английским – я помогу.
http://mail.lag.net/mailman/listinfo/paramiko



Офлайн

#7 Май 10, 2007 19:32:21

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

threading vs. paramiko

ods
Есть подозрение, что paramiko (или модуль, который он использует для SSH) далеко не thread-safe. Обычно такие вещи указываются в документации. Пока что все ошибки возникают в методе connect - можно попробовать устанавливать lock перед его вызовом и снимать после. Есть небольшой шанс, что поможет. Но это неправильный подход: часто бывает, что код вполне работает, пока не наскочишь на неприятное место, и будешь потом долго биться с отладкой. Правиль перед использованием любого модуля в многопоточном приложении узнать точно (прочитав документацию), какие части его бузопасны для использования в разных потоках.
Ну и, конечно же, fork спасёт в любом случае :)
По умолчанию на Линуксе paramiko использует стандартный ssh-client. Однако может использовать и внутреннюю питон-имплементацию протокола при наличи модуля pycrypto. Попробуйте попереключать клиентскую часть.



Отредактировано (Май 10, 2007 19:33:43)

Офлайн

#8 Май 11, 2007 09:12:52

jan2ary
От:
Зарегистрирован: 2006-11-21
Сообщения: 49
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

bialix
По умолчанию на Линуксе paramiko использует стандартный ssh-client. Однако может использовать и внутреннюю питон-имплементацию протокола при наличи модуля pycrypto. Попробуйте попереключать клиентскую часть.
pycrypto имеется, попробую другой вариант.
По поводу лока коннекта - за ночь додумался до этого, сейчас буду пробовать. Конечно, сначала доки почитаю…



Офлайн

#9 Май 11, 2007 10:25:00

jan2ary
От:
Зарегистрирован: 2006-11-21
Сообщения: 49
Репутация: +  0  -
Профиль   Отправить e-mail  

threading vs. paramiko

В доках ничего не нашел про потокобезопасность.
Зато быстро переделал под форканье, работает на ура. Будет время - поиграюсь еще, пока работает так.
Всем спасибо.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version