paramiko是用python語(yǔ)言寫的一個(gè)模塊,遵循SSH2協(xié)議弟胀,支持以加密和認(rèn)證的方式楷力,進(jìn)行遠(yuǎn)程服務(wù)器的連接。paramiko支持Linux, Solaris, BSD, MacOS X, Windows等平臺(tái)通過(guò)SSH從一個(gè)平臺(tái)連接到另外一個(gè)平臺(tái)孵户。利用該模塊萧朝,可以方便的進(jìn)行ssh連接和sftp協(xié)議進(jìn)行sftp文件傳輸。
一夏哭、paramiko模塊的安裝
paramiko模塊依賴PyCrypto模塊检柬,而PyCrypto需要GCC庫(kù)編譯,不過(guò)一般發(fā)行版的源里帶有該模塊竖配。這里以u(píng)buntu為例何址,直接借助以下命令可以直接完成安裝:
sudo pip3 install paramiko
二酱固、paramiko的連接
使用paramiko模塊有兩種連接方式,一種是通過(guò)paramiko.SSHClient()函數(shù)头朱,另外一種是通過(guò)paramiko.Transport()函數(shù)。
方法一:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("某IP地址",22,"用戶名", "口令")
上面的第二行代碼的作用是允許連接不在know_hosts文件中的主機(jī)龄减。
方法二:
import paramiko
t = paramiko.Transport(("主機(jī)","端口"))
t.connect(username = "用戶名", password = "口令")
如果連接遠(yuǎn)程主機(jī)需要提供密鑰项钮,上面第二行代碼可改成:
t.connect(username = "用戶名", password = "口令", hostkey="密鑰")
三、paramiko ssh連接
以下是一個(gè)簡(jiǎn)單的通過(guò)paramiko模塊定義的ssh連接并執(zhí)行命令的函數(shù)希停,如下:
#!/usr/bin/python3
#-*- 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") #interact with server, typing Y
print(stdout.read())
# for x in stdout.readlines():
# print x.strip("n")
print('%s OK\n'%(ip))
ssh.close()
except :
print('%s Error\n' %(ip))
ssh2("45.76.22.112","root","password","ls")
其中第四行的日志部分烁巫,是記錄ssh連接交互時(shí)的一些信息,可以看做是類似于debug的輸出宠能,一般情況下不需要開(kāi)啟亚隙。
stdin.write部分是用于交互情況下,通過(guò)該命令可以執(zhí)行交互违崇。注意這里可能會(huì)引起歧義阿弃,這里的交互并不是ssh連接過(guò)程中出現(xiàn)的讓輸入yes的交互,因?yàn)閜aramiko模塊在連接過(guò)程中會(huì)自動(dòng)處理好yes確認(rèn)羞延。這里的交互是指后面的cmd需要的執(zhí)行的程序可能出現(xiàn)交互的情況下渣淳,可以通過(guò)該參數(shù)進(jìn)行交互。
stdout標(biāo)準(zhǔn)輸出伴箩,在輸出內(nèi)容比較少時(shí)入愧,可以通過(guò)直接使用read讀取出所有的輸出;但在輸出內(nèi)容比較多時(shí)嗤谚,建議通過(guò)按行讀取進(jìn)行處理棺蛛。不過(guò)按行讀取時(shí),每行結(jié)尾會(huì)有換行符n巩步,這樣輸出的結(jié)果很不美觀旁赊。可以通過(guò)strip進(jìn)行字符串的處理渗钉。
在函數(shù)調(diào)用過(guò)程中需要注意的是彤恶,**IP、username鳄橘、passwd都是屬于字符串型的声离,所以需要加引號(hào)。后面執(zhí)行的cmd瘫怜,如果有多個(gè)命令需要操作時(shí)术徊,需要通過(guò)分號(hào)進(jìn)行分割。
四鲸湃、paramiko sftp示例
單個(gè)文件小傳下載的示例:
import paramiko
#建立一個(gè)加密的管道
scp=paramiko.Transport(('192.168.0.102',22))
#建立連接
scp.connect(username='root',password='361way')
#建立一個(gè)sftp客戶端對(duì)象赠涮,通過(guò)ssh transport操作遠(yuǎn)程文件
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()
一個(gè)目錄下多個(gè)文件上傳下載的示例:
#!/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!"
注:本處的目錄下所有文件進(jìn)行下載或上傳的示例中子寓,在遇到目錄下還有嵌套的目錄存在時(shí),會(huì)將目錄也當(dāng)做文件進(jìn)行處理笋除,所以如果想要更加的完美的話斜友,可以通過(guò)引入stat模塊下的S_ISDIR方法進(jìn)行處理
paramiko.transport對(duì)象也支持以socket的方式進(jìn)行連接,如下示例:
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實(shí)現(xiàn)ssh的交互式連接
以下是通過(guò)paramiko模塊直接用ssh協(xié)議登陸到遠(yuǎn)程服務(wù)器的操作代碼鲜屏,這里先定義一個(gè)interactive模塊,代碼如下:
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
代碼內(nèi)容可以從paramiko 在github項(xiàng)目上的demo里獲取国拇。再另外寫一個(gè)ssh_inter.py的交互主程序洛史,內(nèi)容如下:
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)
#關(guān)閉連接
channel.close()
ssh.close()
執(zhí)行效果就像我們平時(shí)直接使用ssh登錄一樣。
六酱吝、總結(jié)
paramiko模塊是一個(gè)比較強(qiáng)大的ssh連接模塊也殖,以上的示例只是列出了該模塊的一些簡(jiǎn)單的使用方法,還可以使用threading模塊加塊程序并發(fā)的速度务热;也可以使用configparser模塊處理配置文件忆嗜,而我們將所有IP、用戶信息操作都放入配置文件崎岂;使用setproctitle模塊為執(zhí)行的程序加一個(gè)容易區(qū)分的title等霎褐。
同樣,雖然連fabric這樣大名鼎鼎的軟件使用的ssh都是用paramiko模塊進(jìn)行的封裝该镣,不過(guò)你依然可以選擇不使用它冻璃,你也可以選擇pexpect模塊實(shí)現(xiàn)封裝一個(gè)簡(jiǎn)易的ssh連接工具、或者使用同樣比較火的salt-ssh模塊损合。