paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。paramiko支持Linux, Solaris, BSD, MacOS X, Windows等平台通过SSH从一个平台连接到另外一个平台。利用该模块,可以方便的进行ssh连接和sftp协议进行sftp文件传输。
一、安装
paramiko模块依赖PyCrypto模块,而PyCrypto需要GCC库编译,不过一般发行版的源里带有该模块。centos6,直接借助以下命令可以直接完成安装:
-
# yum install gcc python-crypto python-paramiko python-devel -y
windows的话,可以下载二进制包
PyCrypto:http://www.voidspace.org.uk/python/pycrypto-2.6.1/ 下一步下一步安装即可
paramiko:https://pypi.python.org/pypi/paramiko/1.7.4 解压缩,然后进入解压缩目录,在DOS下执行
python setup.py build python setup.py install
或者
pip install paramiko
二、paramiko的连接
使用paramiko模块有两种连接方式,一种是通过paramiko.SSHClient()函数,另外一种是通过paramiko.Transport()函数。
方法一:
1
2
3
4
|
import
paramiko
ssh
=
paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
"某IP地址"
,
22
,
"用户名"
,
"口令"
)
|
上面的第二行代码的作用是允许连接不在know_hosts文件中的主机。
方法二:
1
2
3
|
import
paramiko
t
=
paramiko.Transport((
"主机"
,
"端口"
))
t.connect(username
=
"用户名"
, password
=
"口令"
)
|
如果连接远程主机需要提供密钥,上面第二行代码可改成:
1
|
t.connect(username
=
"用户名"
, password
=
"口令"
, hostkey
=
"密钥"
)
|
三、paramiko ssh连接
以下是一个简单的通过paramiko模块定义的ssh连接并执行命令的函数,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/usr/bin/python
#-*- coding: utf-8 -*-
import
paramiko
#paramiko.util.log_to_file('/tmp/sshout')
def
ssh2(ip,username,passwd,cmd):
try
:
ssh
=
paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,
22
,username,passwd,timeout
=
5
)
stdin,stdout,stderr
=
ssh.exec_command(cmd)
# stdin.write("Y") #简单交互,输入 ‘Y’
print
stdout.read()
# for x in stdout.readlines():
# print x.strip("n")
print
'%stOKn'
%
(ip)
ssh.close()
except
:
print
'%stErrorn'
%
(ip)
ssh2(
"192.168.0.102"
,
"root"
,
"361way"
,
"hostname;ifconfig"
)
ssh2(
"192.168.0.107"
,
"root"
,
"123456"
,
"ifconfig"
)
|
其中第四行的日志部分,是记录ssh连接交互时的一些信息,可以看做是类似于debug的输出,一般情况下不需要开启。
stdin.write部分是用于交互情况下,通过该命令可以执行交互。注意这里可能会引起歧义,这里的交互并不是ssh连接过程中出现的让输入yes的交互,因为paramiko模块在连接过程中会自动处理好yes确认。这里的交互是指后面的cmd需要的执行的程序可能出现交互的情况下,可以通过该参数进行交互。
stdout标准输出,在输出内容比较少时,可以通过直接使用read读取出所有的输出;但在输出内容比较多时,建议通过按行读取进行处理。不过按行读取时,每行结尾会有换行符n,这样输出的结果很不美观。可以通过strip进行字符串的处理。
在函数调用过程中需要注意的是,IP、username、passwd都是属于字符串型的,所以需要加引号。后面执行的cmd,如果有多个命令需要操作时,需要通过分号进行分割。
四、paramiko sftp示例
单个文件小传下载的示例:
1
2
3
4
5
6
7
8
9
10
11
12
|
import
paramiko
#建立一个加密的管道
scp
=
paramiko.Transport((
'192.168.0.102'
,
22
))
#建立连接
scp.connect(username
=
'root'
,password
=
'361way'
)
#建立一个sftp客户端对象,通过ssh transport操作远程文件
sftp
=
paramiko.SFTPClient.from_transport(scp)
#Copy a remote file (remotepath) from the SFTP server to the local host
sftp.get(
'/root/testfile'
,
'/tmp/361way'
)
#Copy a local file (localpath) to the SFTP server as remotepath
sftp.put(
'/root/crash-6.1.6.tar.gz'
,
'/tmp/crash-6.1.6.tar.gz'
)
scp.close()
|
一个目录下多个文件上传下载的示例:
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
|
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import
paramiko,datetime,os
hostname
=
'192.168.0.102'
username
=
'root'
password
=
'361way'
port
=
22
local_dir
=
'/tmp/getfile'
remote_dir
=
'/tmp/abc'
try
:
t
=
paramiko.Transport((hostname,port))
t.connect(username
=
username,password
=
password)
sftp
=
paramiko.SFTPClient.from_transport(t)
#files=sftp.listdir(dir_path)
files
=
sftp.listdir(remote_dir)
for
f
in
files:
print
''
print
'#########################################'
print
'Beginning to download file from %s %s '
%
(hostname,datetime.datetime.now())
print
'Downloading file:'
,os.path.join(remote_dir,f)
sftp.get(os.path.join(remote_dir,f),os.path.join(local_dir,f))
#下载
#sftp.put(os.path.join(local_dir,f),os.path.join(remote_dir,f))#上传
print
'Download file success %s '
%
datetime.datetime.now()
print
''
print
'##########################################'
t.close()
except
Exception:
print
"connect error!"
|
注:本处的目录下所有文件进行下载或上传的示例中,在遇到目录下还有嵌套的目录存在时,会将目录也当做文件进行处理,所以如果想要更加的完美的话,可以通过引入stat模块下的S_ISDIR方法进行处理
paramiko.transport对象也支持以socket的方式进行连接,如下示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
paramiko
transport
=
paramiko.Transport((
'localhost'
,
22
))
transport.connect(username
=
'root'
, password
=
'password'
)
sftp
=
paramiko.SFTPClient.from_transport(transport)
sftp.get(remotefile,localfile)
#如果是上传则用:
#sftp.put(localfile, remotefile)
transport.close()
#用socket连接
tcpsock
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpsock.settimeout(
5
)
tcpsock.connect((ip,
22
),)
ssh
=
paramiko.Transport(tcpsock)
ssh.connect(username
=
user,password
=
password)
sftpConnect
=
paramiko.SFTPClient.from_transport(ssh)
|
五、利用paramiko实现ssh的交互式连接
以下是通过paramiko模块直接用ssh协议登陆到远程服务器的操作代码,这里先定义一个interactive模块,代码如下:
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
52
53
54
55
56
57
58
59
60
61
62
63
64
|
import
socket
import
sys
# windows does not have termios...
try
:
import
termios
import
tty
has_termios
=
True
except
ImportError:
has_termios
=
False
def
interactive_shell(chan):
if
has_termios:
posix_shell(chan)
else
:
windows_shell(chan)
def
posix_shell(chan):
import
select
oldtty
=
termios.tcgetattr(sys.stdin)
try
:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
chan.settimeout(
0.0
)
while
True
:
r, w, e
=
select.select([chan, sys.stdin], [], [])
if
chan
in
r:
try
:
x
=
chan.recv(
1024
)
if
len
(x)
=
=
0
:
print
'rn*** EOFrn'
,
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)
# thanks to Mike Looijmans for this code
def
windows_shell(chan):
import
threading
sys.stdout.write(
"Line-buffered terminal emulation. Press F6 or ^Z to send EOF.rnrn"
)
def
writeall(sock):
while
True
:
data
=
sock.recv(
256
)
if
not
data:
sys.stdout.write(
'rn*** EOF ***rnrn'
)
sys.stdout.flush()
break
sys.stdout.write(data)
sys.stdout.flush()
writer
=
threading.Thread(target
=
writeall, args
=
(chan,))
writer.start()
try
:
while
True
:
d
=
sys.stdin.read(
1
)
if
not
d:
break
chan.send(d)
except
EOFError:
# user hit ^Z or F6
pass
|
代码内容可以从paramiko 在github项目上的demo里获取。再另外写一个ssh_inter.py的交互主程序,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
paramiko
import
interactive
#记录日志
paramiko.util.log_to_file(
'/tmp/test'
)
#建立ssh连接
ssh
=
paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
'192.168.0.102'
,port
=
22
,username
=
'root'
,password
=
'xxxxxx'
,compress
=
True
)
#建立交互式shell连接
channel
=
ssh.invoke_shell()
#建立交互式管道
interactive.interactive_shell(channel)
#关闭连接
channel.close()
ssh.close()
|
执行效果就像我们平时直接使用ssh登录一样。
六、总结
paramiko模块是一个比较强大的ssh连接模块,以上的示例只是列出了该模块的一些简单的使用方法,还可以使用threading模块加块程序并发的速度;也可以使用configparser模块处理配置文件,而我们将所有IP、用户信息操作都放入配置文件;使用setproctitle模块为执行的程序加一个容易区分的title等。
同样,虽然连fabric这样大名鼎鼎的软件使用的ssh都是用paramiko模块进行的封装,不过你依然可以选择不使用它,你也可以选择pexpect模块实现封装一个简易的ssh连接工具、或者使用同样比较火的salt-ssh模块。
本文转自 baby神 51CTO博客,原文链接:http://blog.51cto.com/babyshen/1887832,如需转载请自行联系原作者