2013-11-22 43 views
9

私はSSH接続にparamikoを使用するテストケースを探しています。テストケースには、通常、paramiko.exec_command()コールが含まれています(これはrun_command()と呼ばれます)。ここでself.sshは、paramiko.SSHClient()のintanceです。私はデコレータを使用して、各呼び出しの前にssh接続を確認します。それは時々起こることが私のリモートノードが再起動するまで、完璧に動作paramiko SSHチャネルが切断されているかどうかを知る方法?

def check_connections(function): 
    ''' A decorator to check SSH connections. ''' 
    def deco(self, *args, **kwargs): 
     if self.ssh is None: 
      self.ssh = self.get_ssh() 
     else: 
      ret = getattr(self.ssh.get_transport(), 'is_active', None) 
      if ret is None or (ret is not None and not ret()): 
       self.ssh = self.get_ssh() 
     return function(self, *args, **kwargs) 
    return deco 
@check_connections 
def run_command(self, command): 
    ''' Executes command via SSH. ''' 
    stdin, stdout, stderr = self.ssh.exec_command(command) 
    stdin.flush() 
    stdin.channel.shutdown_write() 
    ret = stdout.read() 
    err = stderr.read() 
    if ret: 
     return ret 
    elif err: 
     return err 
    else: 
     return None 

self.get_ssh()は、接続をネゴシエート)。それが発生すると、次のrun_command()コールはsocket.error例外を生成します。問題はparamiko.Transportオブジェクトは例外がスローされるまでアクティブな状態のままにしているように見えることを、次のとおりです。

Python 2.7.3 (default, Mar 7 2013, 14:03:36) 
[GCC 4.3.4 [gcc-4_3-branch revision 152973]] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import os 
>>> import paramiko 
>>> ssh = paramiko.SSHClient() 
>>> print ssh 
<paramiko.SSHClient object at 0x7f2397b96d50> 
>>> print ssh.get_transport() 
None 
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
>>> ssh.load_host_keys(os.path.expanduser('~') + '/.ssh/known_hosts') 
>>> ssh.connect(hostname = '172.31.77.57', username = 'root', password = 'rootroot', timeout = 5.0) 
>>> print ssh 
<paramiko.SSHClient object at 0x7f2397b96d50> 
>>> print ssh.get_transport() 
<paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))> 
>>> print ssh.get_transport().is_active() 
True 
>>> ssh.exec_command('ls') 
(<paramiko.ChannelFile from <paramiko.Channel 1 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>, <paramiko.ChannelFile from <paramiko.Channel 1 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>, <paramiko.ChannelFile from <paramiko.Channel 1 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>) 
>>> print ssh 
<paramiko.SSHClient object at 0x7f2397b96d50> 
>>> print ssh.get_transport() 
<paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))> 
>>> print ssh.get_transport().is_active() 
True 
>>> ssh.exec_command('reboot') 
(<paramiko.ChannelFile from <paramiko.Channel 2 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>, <paramiko.ChannelFile from <paramiko.Channel 2 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>, <paramiko.ChannelFile from <paramiko.Channel 2 (open) window=2097152 -> <paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>) 
>>> print ssh 
<paramiko.SSHClient object at 0x7f2397b96d50> 
>>> print ssh.get_transport() 
<paramiko.Transport at 0x97537550L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))> 
>>> print ssh.get_transport().is_active() 
True 
>>> ssh.exec_command('ls') 
No handlers could be found for logger "paramiko.transport" 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/home/pytest/lib/python2.7/site-packages/paramiko/client.py", line 370, in exec_command 
    chan = self._transport.open_session() 
    File "/home/pytest/lib/python2.7/site-packages/paramiko/transport.py", line 662, in open_session 
    return self.open_channel('session') 
    File "/home/pytest/lib/python2.7/site-packages/paramiko/transport.py", line 764, in open_channel 
    raise e 
socket.error: [Errno 104] Connection reset by peer 
>>> print ssh 
<paramiko.SSHClient object at 0x7f2397b96d50> 
>>> print ssh.get_transport() 
<paramiko.Transport at 0x97537550L (unconnected)> 
>>> print ssh.get_transport().is_active() 
False 
>>> 

質問:どのように私は、接続が本当に有効かそうでないことを確認することができますか?

答えて

8

pythonでは、easier to ask for forgiveness than permissionです。

ラップそうのようなssh.exec_commandへの各呼び出し:

try: 
    ssh.exec_command('ls') 
except socket.error as e: 
    # Crap, it's closed. Perhaps reopen and retry? 
+0

+1それは私のための解決策よりもむしろ回避策です...私はparamikoが必要なものを欠いていると思います... – Milo

+1

@milo - あなたはParamikoにもっと良い解決策を見つけましたか?私はあなたとまったく同じ位置にいます。 –

+0

いいえ、私は最近それについての研究を行っていません。私はそれがこのように行われなければならないと思います。 (返事が遅いのは申し訳ありません) – Milo

2

私のソリューションあなたと基本的に同じ、ちょうど異なっ整理:

def connection(self): 
    if not self.is_connected(): 
     self._ssh = paramiko.SSHClient() 
     self._ssh.connect(self.server, self.port, 
          username = self.username, password = self.password) 

    return self._ssh 

def is_connected(self): 
    transport = self._ssh.get_transport() if self._ssh else None 
    return transport and transport.is_active() 

def do_something(self): 
    self.connection().exec_command('ls') 
1

これは動作します。しかし

import paramiko 
client = paramiko.SSHClient() 
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # Setting the missing host policy to auto add it 
client.connect('192.168.1.16', port=22, username='admin', password='admin', timeout=3, banner_timeout=2) 

channel = client.invoke_shell()     # Request an interactive shell session on this channel. If the server allows it, the channel will then be directly connected to the stdin, stdout, and stderr of the shell. 
print channel.closed   # False 
command = 'reboot' 
channel.send(command + '\n') 
# wait a while 
print channel.closed   # True 
関連する問題