Python3之paramiko模块
Python3之paramiko模块
一. 简介
paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。
二. 使用
1. 下载安装
1
2
3
|
pycrypto,由于 paramiko 模块内部依赖pycrypto,所以先下载安装pycrypto pip3 install pycrypto pip3 install paramiko |
2. 模块使用
SSHClient:
远程连接分为两种:(1)基于用户名密码连接 (2)基于公钥秘钥连接
通过是用paramiko远程操作,其实本质也分为两种:(1)只用SSHClient (2)自己创建一个transport
(1)基于用户名和密码的连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname = 'c1.salt.com' , port = 22 , username = 'GSuser' , password = '123' ) # 执行命令 stdin, stdout, stderr = ssh.exec_command( 'ls' ) # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close() |
SSHClient 封装 Transport
1
2
3
4
5
6
7
8
9
10
11
12
|
import paramiko transport = paramiko.Transport(( 'hostname' , 22 )) transport.connect(username = 'GSuser' , password = '123' ) ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command( 'df' ) print (stdout.read()) transport.close() |
(2)基于公钥秘钥连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import paramiko private_key = paramiko.RSAKey.from_private_key_file( '/home/auto/.ssh/id_rsa' ) # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname = 'c1.salt.com' , port = 22 , username = 'wupeiqi' , key = private_key) # 执行命令 stdin, stdout, stderr = ssh.exec_command( 'df' ) # 获取命令结果 result = stdout.read() # 关闭连接 ssh.close() |
SSHClient 封装Transport
1
2
3
4
5
6
7
8
9
|
import paramiko private_key = paramiko.RSAKey.from_private_key_file( '/home/auto/.ssh/id_rsa' ) transport = paramiko.Transport(( 'hostname' , 22 )) transport.connect(username = 'wupeiqi' , pkey = private_key) ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command( 'df' ) transport.close() |
SFTPClient:
用于连接远程服务器并进行上传下载功能。
(1)基于用户名密码上传下载
1
2
3
4
5
6
7
8
9
10
11
12
|
import paramiko transport = paramiko.Transport(( 'hostname' , 22 )) transport.connect(username = 'GSuser' ,password = '123' ) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put( '/tmp/location.py' , '/tmp/test.py' ) # 将remove_path 下载到本地 local_path sftp.get( 'remove_path' , 'local_path' ) transport.close() |
(2)基于公钥秘钥上传下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import paramiko private_key = paramiko.RSAKey.from_private_key_file( '/home/auto/.ssh/id_rsa' ) transport = paramiko.Transport(( 'hostname' , 22 )) transport.connect(username = 'GSuser' , pkey = private_key ) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put( '/tmp/location.py' , '/tmp/test.py' ) # 将remove_path 下载到本地 local_path sftp.get( 'remove_path' , 'local_path' ) transport.close() |
Demo: 实现远程命令执行和文件上传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#!/usr/bin/env python # -*- coding:utf-8 -*- import paramiko class SSHConnection( object ): def __init__( self , host = '192.168.12.68' , port = 22 , username = 'locojoy' ,pwd = '123321QQ!' ): self .host = host self .port = port self .username = username self .pwd = pwd self .__k = None def run( self ): self .connect() # 连接远程服务器 self .upload( 'db.py' , '/tmp/1.py' ) # 将本地的db.py文件上传到远端服务器的/tmp/目录下并改名为1.py self .cmd( 'df' ) # 执行df 命令 self .close() # 关闭连接 def connect( self ): transport = paramiko.Transport(( self .host, self .port)) transport.connect(username = self .username, password = self .pwd) self .__transport = transport def close( self ): self .__transport.close() def upload( self ,local_path,target_path): sftp = paramiko.SFTPClient.from_transport( self .__transport) sftp.put(local_path,target_path) def cmd( self , command): ssh = paramiko.SSHClient() ssh._transport = self .__transport # 执行命令 stdin, stdout, stderr = ssh.exec_command(command) # 获取命令结果 result = stdout.read() print (result) return result obj = SSHConnection() obj.run() |
paramiko在堡垒机中的应用
(1)简单实例:远程连接一台主机,操作命令,linux版本,输入终端为回车则发送命令。不支持tab补全功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import paramiko, sys, os, socket, select, getpass from paramiko.py3compat import u # 在python3中是这样使用的,如果在Python2中则注释这行 # 这个程序依赖于终端,只能在Liunx下运行,windows用其他的方式 tran = paramiko.Transport(( '192.168.12.68' , 22 ,)) tran.start_client() tran.auth_password( 'locojoy' , '123321QQ!' ) # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() # 原始的方法利用终端进行收发消息 # 利用sys.stdin,肆意妄为执行操作 # 用户在终端输入内容,并将内容发送至远程服务器 # 远程服务器执行命令,并将结果返回 # 用户终端显示内容 while True : # 监视用户输入和服务器返回数据 # sys.stdin 处理用户输入 # chan 是之前创建的通道,用于接收服务器返回信息 # 通过select监听终端(输入输出),一旦变化,就将拿到的数据发送给服务器 # 通过监听socket句柄,如果有变化表示服务器要给我发消息 readable, writeable, error = select.select([chan, sys.stdin, ],[],[], 1 ) # 通过select.select 监听chan(打开的通道(和远程服务器连接的状态)), sys.stdin(输入),一旦变化就写入readable # 当chan变化时,加入到readable,远程服务器发送内容过来 if chan in readable: try : x = u(chan.recv( 1024 )) # Python3用这个 # x = chan.recv(1024) Python2使用这个 if len (x) = = 0 : print ( '\r\n*** EOF\r\n' ) break sys.stdout.write(x) # 写入缓冲区 sys.stdout.flush() # 刷新,将缓冲区内容显示出来 except socket.timeout: pass # 当sys.stdin 放入readable中时,将获取到的内容发送到远程服务器 if sys.stdin in readable: inp = sys.stdin.readline() chan.sendall(inp) chan.close() tran.close() |
(2)每按一个键就发送记录,并支持tab自动补全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
import paramiko, sys, os, socket, select, getpass, termios, tty from paramiko.py3compat import u tran = paramiko.Transport(( '10.211.55.4' , 22 ,)) tran.start_client() tran.auth_password( 'wupeiqi' , '123' ) # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() # 获取原tty属性 oldtty = termios.tcgetattr(sys.stdin) try : # 为tty设置新属性 # 默认当前tty设备属性: # 输入一行回车,执行 # CTRL+C 进程退出,遇到特殊字符,特殊处理。 # 这是为原始模式,不认识所有特殊符号 # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器 tty.setraw(sys.stdin.fileno()) # 恢复终端原始状态,每按一个键就发送 chan.settimeout( 0.0 ) while True : # 监视 用户输入 和 远程服务器返回数据(socket) # 阻塞,直到句柄可读 r, w, e = select.select([chan, sys.stdin], [], [], 1 ) if chan in r: # 获取服务返回的内容 try : x = u(chan.recv( 1024 )) if len (x) = = 0 : print ( '\r\n*** EOF\r\n' ) break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if sys.stdin in r: # 发送命令 x = sys.stdin.read( 1 ) # 读取一个字符 if len (x) = = 0 : break chan.send(x) # 发送一个字符 finally : # 重新设置终端属性,将终端状态还原 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) chan.close() tran.close() |