【问题标题】:Python paramiko module using multiple commands使用多个命令的 Python paramiko 模块
【发布时间】:2013-11-11 15:45:55
【问题描述】:

我有一个创建连接的类。我可以在通道关闭之前连接并执行 1 个命令。在我拥有的另一个系统上,我可以执行多个命令并且通道不会关闭。显然这是我尝试连接的系统的配置问题。

class connect:

    newconnection = ''

    def __init__(self,username,password): 
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh.connect('somehost', username=username,password=password,port=2222,timeout=5)
        except:
            print "Count not connect"
            sys.exit()
        self.newconnection = ssh

    def con(self):
        return self.newconnection

然后我使用'ls'命令来打印一些输出

sshconnection = connect('someuser','somepassword').con()


stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")

print stdout.readlines() 
print stdout 

stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")

print stdout.readlines() 
print stdout 

sshconnection.close()
sys.exit()

在第一个 exec_command 运行后,它会打印 dir 列表的预期输出。当我在第一个 exec_command 之后打印 stdout 时,看起来通道已关闭

<paramiko.ChannelFile from <paramiko.Channel 1 (closed) -> <paramiko.Transport at 0x2400f10L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))>>> 

就像我在另一个系统上所说的那样,我能够继续运行命令并且连接不会关闭。有没有办法让我保持打开状态?或者更好的方法我可以看到它关闭的原因?

编辑:所以看起来每个 SSHClient.exec_command 只能运行 1 个命令...所以我决定 get_transport().open_session() 然后运行一个命令。第一个总是有效的。第二个总是失败,脚本只是挂起

【问题讨论】:

  • 您找到了很好的解决方案吗?我在输出中获得了多个 exec_command 的开放通道消息。第一个命令工作正常。问题在于随后的后续。
  • @Drt 不幸的是,看起来 exec_command 在关闭通道之前只会运行一个命令。即使我试图运行下一个命令,它也会告诉我我的频道已打开。但是该命令不会执行。我尝试了织物,它在与我尝试使用它的系统不同的系统上工作。如果您将它用于基本的 ssh 连接结构,应该会更好。或查看木偶
  • 我找到了解决方案。我在打印时只使用了stdout,忘记了我需要使用stdout.read。非常轻微的错误。你可以参考这里this is the question I raised

标签: python ssh paramiko


【解决方案1】:

exec_command 执行后,只有paramiko 会关闭通道,ssh 返回身份验证提示。

似乎只使用paramiko 是不可能的,试试fabric 或其他工具。

** fabric did not work out too.

【讨论】:

  • 不,它没有。不过,自从我从事那个项目以来已经有很长时间了。也许 paramiko 或织物从那以后发生了变化,但当时它不起作用
【解决方案2】:

请参阅以下参考,因为它提供了在 Paramiko 中执行此操作的方法:

How do you execute multiple commands in a single session in Paramiko? (Python)

【讨论】:

    【解决方案3】:

    可以使用 netmiko(在 Windows 上测试)。 此示例是为连接 cisco 设备而编写的,但原理也适用于其他设备。

    import netmiko
    from netmiko import ConnectHandler
    import json
    
    def connect_enable_silent(ip_address,ios_command):
        with open ("credentials.txt") as line:
            line_1 = json.load(line)
            for k,v in line_1.items():
                router=(k,v)
                try:
                    ssh = ConnectHandler(**router[1],device_type="cisco_ios",ip=ip_address)
                    ssh.enable()
                except netmiko.ssh_exception.NetMikoAuthenticationException:
                    #incorrect credentials
                    continue
                except netmiko.ssh_exception.NetMikoTimeoutException:
                    #oddly enough if it can log in but not able to authenticate to enable mode the ssh.enable() command does not give an authentication error
                    #but a time-out error instead
                    try:
                        ssh = ConnectHandler(username = router[1]['username'],password = router[1]['password'],device_type="cisco_ios", ip=ip_address)
                    except netmiko.ssh_exception.NetMikoTimeoutException:
                        # connection timed out (ssh not enabled on device, try telnet)
                        continue
                    except Exception:
                        continue
                    else:
                        output = ssh.send_command(ios_command)
                        ssh.disconnect()
                        if "at '^' marker." in output:
                            #trying to run a command that requires enble mode but not authenticated to enable mode
                            continue
                        return output
                except Exception:
                    continue
                else:
                    output = ssh.send_command(ios_command)
                    ssh.disconnect()
                    return output
    
    output = connect_enable_silent(ip_address,ios_command)
    for line in output.split('\n'):
        print(line)
    

    凭据文本旨在存储不同的凭据,以防您打算调用此函数来访问多个设备,而不是所有设备都使用相同的凭据。格式为:

    {"credentials_1":{"username":"username_1","password":"password_1","secret":"secret_1"},
    "credentials_2":{"username":"username_2","password":"password_2","secret":"secret_2"},
    "credentials_3": {"username": "username_3", "password": "password_3"}
    }
    

    可以更改异常以执行不同的操作,在我的情况下,我只需要它不返回错误并继续尝试下一组,这就是大多数异常被静音的原因。

    【讨论】:

    • 我也改用了类似的东西——谢谢你发布这个!对于 quick-n-dirty ssh 会话,netmiko 是一个不错的选择。